Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 1,637 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Deposit As Colla... | 50816218 | 4 hrs ago | IN | 0 MON | 0.03169885 | ||||
| Redeem | 50815750 | 4 hrs ago | IN | 0 MON | 0.07327039 | ||||
| Redeem | 50805415 | 5 hrs ago | IN | 0 MON | 0.10504378 | ||||
| Deposit As Colla... | 50752945 | 11 hrs ago | IN | 0 MON | 0.06226579 | ||||
| Deposit As Colla... | 50734401 | 13 hrs ago | IN | 0 MON | 0.03171873 | ||||
| Deposit As Colla... | 50733158 | 13 hrs ago | IN | 0 MON | 0.03674121 | ||||
| Deposit As Colla... | 50732785 | 13 hrs ago | IN | 0 MON | 0.03509146 | ||||
| Deposit As Colla... | 50732506 | 13 hrs ago | IN | 0 MON | 0.03509674 | ||||
| Deposit As Colla... | 50732237 | 13 hrs ago | IN | 0 MON | 0.06227028 | ||||
| Deposit As Colla... | 50720547 | 14 hrs ago | IN | 0 MON | 0.04151104 | ||||
| Deposit As Colla... | 50717278 | 15 hrs ago | IN | 0 MON | 0.04151226 | ||||
| Deposit As Colla... | 50663320 | 21 hrs ago | IN | 0 MON | 0.02818746 | ||||
| Deposit As Colla... | 50659545 | 21 hrs ago | IN | 0 MON | 0.02820259 | ||||
| Deposit As Colla... | 50655605 | 22 hrs ago | IN | 0 MON | 0.04250388 | ||||
| Set Delegate App... | 50636120 | 24 hrs ago | IN | 0 MON | 0.00842826 | ||||
| Set Delegate App... | 50632227 | 24 hrs ago | IN | 0 MON | 0.01387612 | ||||
| Redeem | 50622255 | 25 hrs ago | IN | 0 MON | 0.07327161 | ||||
| Deposit As Colla... | 50617665 | 26 hrs ago | IN | 0 MON | 0.02599943 | ||||
| Redeem | 50616737 | 26 hrs ago | IN | 0 MON | 0.14795268 | ||||
| Deposit As Colla... | 50614388 | 26 hrs ago | IN | 0 MON | 0.02339308 | ||||
| Set Delegate App... | 50614225 | 26 hrs ago | IN | 0 MON | 0.00844131 | ||||
| Set Delegate App... | 50613793 | 26 hrs ago | IN | 0 MON | 0.00942101 | ||||
| Deposit As Colla... | 50613700 | 26 hrs ago | IN | 0 MON | 0.05075792 | ||||
| Set Delegate App... | 50613101 | 26 hrs ago | IN | 0 MON | 0.00834722 | ||||
| Set Delegate App... | 50611354 | 27 hrs ago | IN | 0 MON | 0.01154493 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x92EE4b4d...08aCedBF1 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
BorrowableCToken
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/ERC20.sol
/// @notice Simple ERC20 + EIP-2612 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)
///
/// @dev Note:
/// - The ERC20 standard allows minting and transferring to and from the zero address,
/// minting and transferring zero tokens, as well as self-approvals.
/// For performance, this implementation WILL NOT revert for such actions.
/// Please add any checks with overrides if desired.
/// - The `permit` function uses the ecrecover precompile (0x1).
///
/// If you are overriding:
/// - NEVER violate the ERC20 invariant:
/// the total sum of all balances must be equal to `totalSupply()`.
/// - Check that the overridden function is actually used in the function you want to
/// change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The total supply has overflowed.
error TotalSupplyOverflow();
/// @dev The allowance has overflowed.
error AllowanceOverflow();
/// @dev The allowance has underflowed.
error AllowanceUnderflow();
/// @dev Insufficient balance.
error InsufficientBalance();
/// @dev Insufficient allowance.
error InsufficientAllowance();
/// @dev The permit is invalid.
error InvalidPermit();
/// @dev The permit has expired.
error PermitExpired();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
event Transfer(address indexed from, address indexed to, uint256 amount);
/// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
event Approval(address indexed owner, address indexed spender, uint256 amount);
/// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
uint256 private constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The storage slot for the total supply.
uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;
/// @dev The balance slot of `owner` is given by:
/// ```
/// mstore(0x0c, _BALANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let balanceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;
/// @dev The allowance slot of (`owner`, `spender`) is given by:
/// ```
/// mstore(0x20, spender)
/// mstore(0x0c, _ALLOWANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let allowanceSlot := keccak256(0x0c, 0x34)
/// ```
uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;
/// @dev The nonce slot of `owner` is given by:
/// ```
/// mstore(0x0c, _NONCES_SLOT_SEED)
/// mstore(0x00, owner)
/// let nonceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _NONCES_SLOT_SEED = 0x38377508;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.
uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
bytes32 private constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
/// @dev `keccak256("1")`.
bytes32 private constant _VERSION_HASH =
0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;
/// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`.
bytes32 private constant _PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 METADATA */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the name of the token.
function name() public view virtual returns (string memory);
/// @dev Returns the symbol of the token.
function symbol() public view virtual returns (string memory);
/// @dev Returns the decimals places of the token.
function decimals() public view virtual returns (uint8) {
return 18;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the amount of tokens in existence.
function totalSupply() public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_TOTAL_SUPPLY_SLOT)
}
}
/// @dev Returns the amount of tokens owned by `owner`.
function balanceOf(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
function allowance(address owner, address spender)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x34))
}
}
/// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
///
/// Emits a {Approval} event.
function approve(address spender, uint256 amount) public virtual returns (bool) {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
}
return true;
}
/// @dev Transfer `amount` tokens from the caller to `to`.
///
/// Requirements:
/// - `from` must at least have `amount`.
///
/// Emits a {Transfer} event.
function transfer(address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(msg.sender, to, amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, caller())
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
}
_afterTokenTransfer(msg.sender, to, amount);
return true;
}
/// @dev Transfers `amount` tokens from `from` to `to`.
///
/// Note: Does not update the allowance if it is the maximum uint256 value.
///
/// Requirements:
/// - `from` must at least have `amount`.
/// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
///
/// Emits a {Transfer} event.
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the allowance slot and load its value.
mstore(0x20, caller())
mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
return true;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EIP-2612 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For more performance, override to return the constant value
/// of `keccak256(bytes(name()))` if `name()` will never change.
function _constantNameHash() internal view virtual returns (bytes32 result) {}
/// @dev Returns the current nonce for `owner`.
/// This value is used to compute the signature for EIP-2612 permit.
function nonces(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
// Compute the nonce slot and load its value.
mstore(0x0c, _NONCES_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
/// authorized by a signed approval by `owner`.
///
/// Emits a {Approval} event.
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
// Revert if the block timestamp is greater than `deadline`.
if gt(timestamp(), deadline) {
mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.
revert(0x1c, 0x04)
}
let m := mload(0x40) // Grab the free memory pointer.
// Clean the upper 96 bits.
owner := shr(96, shl(96, owner))
spender := shr(96, shl(96, spender))
// Compute the nonce slot and load its value.
mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
mstore(0x00, owner)
let nonceSlot := keccak256(0x0c, 0x20)
let nonceValue := sload(nonceSlot)
// Prepare the domain separator.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
mstore(0x2e, keccak256(m, 0xa0))
// Prepare the struct hash.
mstore(m, _PERMIT_TYPEHASH)
mstore(add(m, 0x20), owner)
mstore(add(m, 0x40), spender)
mstore(add(m, 0x60), value)
mstore(add(m, 0x80), nonceValue)
mstore(add(m, 0xa0), deadline)
mstore(0x4e, keccak256(m, 0xc0))
// Prepare the ecrecover calldata.
mstore(0x00, keccak256(0x2c, 0x42))
mstore(0x20, and(0xff, v))
mstore(0x40, r)
mstore(0x60, s)
let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
// If the ecrecover fails, the returndatasize will be 0x00,
// `owner` will be checked if it equals the hash at 0x00,
// which evaluates to false (i.e. 0), and we will revert.
// If the ecrecover succeeds, the returndatasize will be 0x20,
// `owner` will be compared against the returned address at 0x20.
if iszero(eq(mload(returndatasize()), owner)) {
mstore(0x00, 0xddafbaef) // `InvalidPermit()`.
revert(0x1c, 0x04)
}
// Increment and store the updated nonce.
sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.
// Compute the allowance slot and store the value.
// The `owner` is already at slot 0x20.
mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
sstore(keccak256(0x2c, 0x34), value)
// Emit the {Approval} event.
log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero pointer.
}
}
/// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Grab the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
result := keccak256(m, 0xa0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL MINT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `amount` tokens to `to`, increasing the total supply.
///
/// Emits a {Transfer} event.
function _mint(address to, uint256 amount) internal virtual {
_beforeTokenTransfer(address(0), to, amount);
/// @solidity memory-safe-assembly
assembly {
let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
let totalSupplyAfter := add(totalSupplyBefore, amount)
// Revert if the total supply overflows.
if lt(totalSupplyAfter, totalSupplyBefore) {
mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.
revert(0x1c, 0x04)
}
// Store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
}
_afterTokenTransfer(address(0), to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL BURN FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Burns `amount` tokens from `from`, reducing the total supply.
///
/// Emits a {Transfer} event.
function _burn(address from, uint256 amount) internal virtual {
_beforeTokenTransfer(from, address(0), amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, from)
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Subtract and store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
// Emit the {Transfer} event.
mstore(0x00, amount)
log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
}
_afterTokenTransfer(from, address(0), amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL TRANSFER FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Moves `amount` of tokens from `from` to `to`.
function _transfer(address from, address to, uint256 amount) internal virtual {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL ALLOWANCE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and load its value.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
}
}
/// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
///
/// Emits a {Approval} event.
function _approve(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
let owner_ := shl(96, owner)
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any transfer of tokens.
/// This includes minting and burning.
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/// @dev Hook that is called after any transfer of tokens.
/// This includes minting and burning.
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
// contracts/libraries/external/FixedPointMathLib.sol
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @dev Reduced function scope from full FixedPointMathLib library to only what is needed for Curvance.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Least significant 256 bits of the product.
result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
let mm := mulmod(x, y, not(0))
// Most significant 256 bits of the product.
let p1 := sub(mm, add(result, lt(mm, result)))
// Handle non-overflow cases, 256 by 256 division.
if iszero(p1) {
if iszero(d) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
result := div(result, d)
break
}
// Make sure the result is less than `2**256`. Also prevents `d == 0`.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
// Compute remainder using mulmod.
let r := mulmod(x, y, d)
// `t` is the least significant bit of `d`.
// Always greater or equal to 1.
let t := and(d, sub(0, d))
// Divide `d` by `t`, which is a power of two.
d := div(d, t)
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
result :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(
mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
div(sub(result, r), t)
),
// inverse mod 2**256
mul(inv, sub(2, mul(d, inv)))
)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
result = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
result := add(result, 1)
if iszero(result) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
}
}
/// @dev Returns the square root of `x`.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
}
// contracts/interfaces/ICentralRegistry.sol
/// TYPES ///
/// @notice Configuration data for a separately supported blockchain.
/// @param isSupported Whether the chain is supported or not.
/// @param messagingChainId Messaging Chain ID where this address authorized.
/// @param domain Domain for the chain.
/// @param messagingHub Messaging Hub address on the chain.
/// @param votingHub Voting Hub address on the chain.
/// @param cveAddress CVE address on the chain.
/// @param feeTokenAddress Fee token address on the chain.
/// @param crosschainRelayer Crosschain relayer address on the chain.
struct ChainConfig {
bool isSupported;
uint16 messagingChainId;
uint32 domain;
address messagingHub;
address votingHub;
address cveAddress;
address feeTokenAddress;
address crosschainRelayer;
}
interface ICentralRegistry {
/// @notice The length of one protocol epoch, in seconds.
function EPOCH_DURATION() external view returns (uint256);
/// @notice Sequencer uptime oracle on this chain (for L2s).
function SEQUENCER_ORACLE() external view returns (address);
/// @notice Returns Genesis Epoch Timestamp of Curvance.
function genesisEpoch() external view returns (uint256);
/// @notice Returns Protocol DAO address.
function daoAddress() external view returns (address);
/// @notice Returns Protocol Emergency Council address.
function emergencyCouncil() external view returns (address);
/// @notice Indicates if address has DAO permissions or not.
function hasDaoPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has elevated DAO permissions or not.
function hasElevatedPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has lock creation permissions or not.
function hasLockingPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has auction permissions or not.
function hasAuctionPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has market permissions or not.
function hasMarketPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has harvest permissions or not.
function hasHarvestPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Returns Reward Manager address.
function rewardManager() external view returns (address);
/// @notice Returns Gauge Manager address.
function gaugeManager() external view returns (address);
/// @notice Returns CVE address.
function cve() external view returns (address);
/// @notice Returns veCVE address.
function veCVE() external view returns (address);
/// @notice Returns Voting Hub address.
function votingHub() external view returns (address);
/// @notice Returns Messaging Hub address.
function messagingHub() external view returns (address);
/// @notice Returns Oracle Manager address.
function oracleManager() external view returns (address);
/// @notice Returns Fee Manager address.
function feeManager() external view returns (address);
/// @notice Returns Fee Token address.
function feeToken() external view returns (address);
/// @notice Returns Crosschain Core contract address.
function crosschainCore() external view returns (address);
/// @notice Returns Crosschain Relayer contract address.
function crosschainRelayer() external view returns (address);
/// @notice Returns Token Messenger contract address.
function tokenMessager() external view returns (address);
/// @notice Returns Messenger Transmitter contract address.
function messageTransmitter() external view returns (address);
/// @notice Returns domain value.
function domain() external view returns (uint32);
/// @notice Returns protocol gas fee on harvest, in `BPS`.
function protocolCompoundFee() external view returns (uint256);
/// @notice Returns protocol yield fee on strategy harvest, in `BPS`.
function protocolYieldFee() external view returns (uint256);
/// @notice Returns protocol yield + gas fee on strategy harvest,
/// in `BPS`.
function protocolHarvestFee() external view returns (uint256);
/// @notice Returns protocol fee on leverage actions, in `BPS`.
function protocolLeverageFee() external view returns (uint256);
/// @notice Returns default fee on interest generated from active loans,
/// in `BPS`.
function defaultProtocolInterestFee() external view returns (uint256);
/// @notice Returns earlyUnlockPenaltyMultiplier value, in `BPS`.
function earlyUnlockPenaltyMultiplier() external view returns (uint256);
/// @notice Returns voteBoostMultiplier value, in `BPS`.
function voteBoostMultiplier() external view returns (uint256);
/// @notice Returns lockBoostMultiplier value, in `BPS`.
function lockBoostMultiplier() external view returns (uint256);
/// @notice Returns swap slippage limit, in `BPS`.
function slippageLimit() external view returns (uint256);
/// @notice Returns an array of Chain IDs recorded in the Crosschain
/// Protocol's Chain ID format.
function foreignChainIds() external view returns (uint256[] memory);
/// @notice Returns an array of Curvance markets on this chain.
function marketManagers() external view returns (address[] memory);
/// @notice Increments a caller's approval index.
/// @dev By incrementing their approval index, a user's delegates will all
/// have their delegation authority revoked across all Curvance
/// contracts.
/// Emits an {ApprovalIndexIncremented} event.
function incrementApprovalIndex() external;
/// @notice Returns `user`'s approval index.
/// @param user The user to check approval index for.
function userApprovalIndex(address user) external view returns (uint256);
/// @notice Returns whether a user has delegation disabled.
/// @param user The user to check delegation status for.
function checkNewDelegationDisabled(
address user
) external view returns (bool);
/// @notice Returns whether a particular GETH chainId is supported.
/// ChainId => messagingHub address, 2 = supported; 1 = unsupported.
function chainConfig(
uint256 chainId
) external view returns (ChainConfig memory);
/// @notice Returns the GETH chainId corresponding chainId corresponding
/// to Crosschain Messaging Protocol's `chainId`.
/// @param chainId The Crosschain Messaging Protocol's chainId.
/// @return The GETH chainId corresponding chainId corresponding to
/// Crosschain Messaging Protocol's `chainId`.
function messagingToGETHChainId(
uint16 chainId
) external view returns (uint256);
/// @notice Returns the Crosschain Messaging Protocol's ChainId
/// corresponding to the GETH `chainId`.
/// @param chainId The GETH chainId.
/// @return The Crosschain Messaging Protocol's ChainId
/// corresponding to the GETH `chainId`.
function GETHToMessagingChainId(
uint256 chainId
) external view returns (uint256);
/// @notice Indicates if an address is a market manager or not.
function isMarketManager(
address addressToCheck
) external view returns (bool);
/// @notice Maps an intent target address to the contract that will
/// inspect provided external calldata.
function externalCalldataChecker(
address addressToCheck
) external view returns (address);
/// @notice Maps a Multicall target address to the contract that will
/// inspect provided multicall calldata.
function multicallChecker(
address addressToCheck
) external view returns (address);
/// @notice Indicates the amount of token rewards allocated on this chain,
/// for an epoch.
function emissionsAllocatedByEpoch(
uint256 epoch
) external view returns (uint256);
/// @notice Indicates the amount of token rewards allocated across all
/// chains, for an era. An era is a particular period in time in
/// which rewards are constant, before a halvening event moves the
/// protocol to a new era.
function targetEmissionAllocationByEra(
uint256 era
) external view returns (uint256);
/// @notice Unlocks a market to process auction-based liquidations.
/// @param marketToUnlock The address of the market manager to unlock
/// auction-based liquidations with a specific
/// liquidation bonus.
function unlockAuctionForMarket(address marketToUnlock) external;
/// @notice Checks if a market is unlocked for auction operations.
/// @return Whether the caller is an unlocked market, approved for
/// auction-based liquidations.
function isMarketUnlocked() external view returns (bool);
/// @notice Sets the amount of token rewards allocated on this chain,
/// for an epoch.
/// @dev Only callable by the Voting Hub.
/// @param epoch The epoch having its token emission values set.
/// @param emissionsAllocated The amount of token rewards allocated on
/// this chain, for an epoch.
function setEmissionsAllocatedByEpoch(
uint256 epoch,
uint256 emissionsAllocated
) external;
/// @notice Checks whether `user` has transferability enabled or disabled
/// for their tokens.
/// @dev This is inherited from ActionRegistry portion of centralRegistry.
/// @param user The address to check whether transferability is enabled or
/// disabled for.
/// @return result Indicates whether `user` has transferability disabled
/// or not, true = disabled, false = not disabled.
function checkTransfersDisabled(
address user
) external view returns (bool result);
}
// contracts/interfaces/IDynamicIRM.sol
interface IDynamicIRM {
/// @notice Returns the interval at which interest rates are adjusted.
/// @notice The interval at which interest rates are adjusted,
/// in seconds.
function ADJUSTMENT_RATE() external view returns (uint256);
/// @notice The borrowable token linked to this interest rate model
/// contract.
function linkedToken() external view returns (address);
/// @notice Calculates the current borrow rate, per second.
/// @dev This function's intention is for frontend data querying and
/// should not be used for onchain execution.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @return result The borrow interest rate percentage, per second,
/// in `WAD`.
function borrowRate(
uint256 assetsHeld,
uint256 debt
) external view returns (uint256 result);
/// @notice Calculates the current borrow rate per second,
/// with updated vertex multiplier applied.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @return result The borrow rate percentage per second, in `WAD`.
function predictedBorrowRate(
uint256 assetsHeld,
uint256 debt
) external view returns (uint256 result);
/// @notice Calculates the current supply rate, per second.
/// @dev This function's intention is for frontend data querying and
/// should not be used for onchain execution.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @param interestFee The current interest rate protocol fee
/// for the market token.
/// @return result The supply interest rate percentage, per second,
/// in `WAD`.
function supplyRate(
uint256 assetsHeld,
uint256 debt,
uint256 interestFee
) external view returns (uint256 result);
/// @notice Calculates the interest rate paid per second by borrowers,
/// in percentage paid, per second, in `WAD`, and updates
/// `vertexMultiplier` if necessary.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @return ratePerSecond The interest rate paid per second by borrowers,
/// in percentage paid, per second, in `WAD`.
/// @return adjustmentRate The period of time at which interest rates are
/// adjusted, in seconds.
function adjustedBorrowRate(
uint256 assetsHeld,
uint256 debt
) external returns (uint256 ratePerSecond, uint256 adjustmentRate);
/// @notice Calculates the borrow utilization rate of the market.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param outstandingDebt The amount of outstanding debt in the pool.
/// @return The utilization rate between [0, WAD].
function utilizationRate(
uint256 assetsHeld,
uint256 outstandingDebt
) external view returns (uint256);
}
// contracts/interfaces/IERC165.sol
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(
bytes4 interfaceId
) external view returns (bool);
}
// contracts/interfaces/IERC20.sol
// @dev Interface of the ERC20 standard
interface IERC20 {
// @dev Returns the name of the token.
function name() external view returns (string memory);
// @dev Returns the symbol of the token.
function symbol() external view returns (string memory);
// @dev Returns the decimals of the token.
function decimals() external view returns (uint8);
// @dev Emitted when `value` tokens are moved from one account (`from`) to
// another (`to`).
// Note that `value` may be zero.
event Transfer(address indexed from, address indexed to, uint256 value);
// @dev Emitted when the allowance of a `spender` for an `owner` is set by
// a call to {approve}. `value` is the new allowance.
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
// @dev Returns the amount of tokens in existence.
function totalSupply() external view returns (uint256);
// @dev Returns the amount of tokens owned by `account`.
function balanceOf(address account) external view returns (uint256);
// @dev Moves `amount` tokens from the caller's account to `to`.
// Returns a boolean value indicating whether the operation succeeded.
// Emits a {Transfer} event.
function transfer(address to, uint256 amount) external returns (bool);
// @dev Moves `amount` tokens from `from` to `to` using the
// allowance mechanism. `amount` is then deducted from the caller's
// allowance.
// Returns a boolean value indicating whether the operation succeeded.
// Emits a {Transfer} event.
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
// @dev Returns the remaining number of tokens that `spender` will be
// allowed to spend on behalf of `owner` through {transferFrom}. This
// is zero by default.
function allowance(
address owner,
address spender
) external view returns (uint256);
// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
// Returns a boolean value indicating whether the operation succeeded.
// IMPORTANT: Beware that changing an allowance with this method brings the risk
// that someone may use both the old and the new allowance by unfortunate
// transaction ordering. One possible solution to mitigate this race
// condition is to first reduce the spender's allowance to 0 and set the
// desired value afterwards:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
// Emits an {Approval} event.
function approve(address spender, uint256 amount) external returns (bool);
}
// contracts/interfaces/IFlashLoan.sol
interface IFlashLoan {
/// @notice The fee to be charged for a given flashloan.
/// @param assets The amount of `asset()` lent during the flashloan.
/// return The assets of `asset()` to be charged for the flashloan.
function flashFee(uint256 assets) external view returns (uint256);
/// @notice Required callback for using a flashloan on Curvance.
/// @param assets The amount of the token loaned during the flashloan.
/// @param assetsReturned The amount of token required to be returned
/// for the flashloan.
/// @param data Arbitrary calldata passed to flashloan callback to execute
/// desired action during the flashloan.
function onFlashLoan(
uint256 assets,
uint256 assetsReturned,
bytes calldata data
) external returns (bytes32);
}
// contracts/interfaces/IMarketManager.sol
interface IMarketManager {
/// TYPES ///
/// @notice Data structure passed communicating the intended liquidation
/// scenario to review based on current liquidity levels.
/// @param collateralToken The token which was used as collateral
/// by `account` and may be seized.
/// @param debtToken The token to potentially repay which has
/// outstanding debt by `account`.
/// @param numAccounts The number of accounts to be, potentially,
/// liquidated.
/// @param liquidateExact Whether the liquidator desires a specific
/// liquidation amount.
/// @param liquidatedShares Empty variable slot to store how much
/// `collateralToken` will be seized as
/// part of a particular liquidation.
/// @param debtRepaid Empty variable slot to store how much
/// `debtToken` will be repaid as part of a
/// particular liquidation.
/// @param badDebt Empty variable slot to store how much bad debt will
/// be realized by lenders as part of a particular
/// liquidation.
struct LiqAction {
address collateralToken;
address debtToken;
uint256 numAccounts;
bool liquidateExact;
uint256 liquidatedShares;
uint256 debtRepaid;
uint256 badDebt;
}
/// @notice Data structure returned communicating outcome of a liquidity
/// scenario review based on current liquidity levels.
/// @param liquidatedShares An array containing the collateral amounts to
/// liquidate from accounts, in shares.
/// @param debtRepaid The total amount of debt to repay from accounts,
/// in assets.
/// @param badDebtRealized The total amount of debt to realize as losses
/// for lenders, in assets.
struct LiqResult {
uint256[] liquidatedShares;
uint256 debtRepaid;
uint256 badDebtRealized;
}
/// @notice Returns whether minting, collateralization, borrowing of
/// `cToken` is paused.
/// @param cToken The address of the Curvance token to return
/// action statuses of.
/// @return bool Whether minting `cToken` is paused or not.
/// @return bool Whether collateralization `cToken` is paused or not.
/// @return bool Whether borrowing `cToken` is paused or not.
function actionsPaused(
address cToken
) external view returns (bool, bool, bool);
/// @notice Returns the current collateralization configuration
/// of `cToken`.
/// @param cToken The address of the Curvance token to return
/// collateralization configuration of.
/// @return The ratio at which this token can be borrowed against
/// when collateralized.
/// @return The collateral requirement where dipping below this
/// will cause a soft liquidation.
/// @return The collateral requirement where dipping below
/// this will cause a hard liquidation.
function collConfig(address cToken) external view returns (
uint256, uint256, uint256
);
/// @notice Returns the current liquidation configuration
/// of `cToken`.
/// @param cToken The address of the Curvance token to return
/// liquidation configuration of.
/// @return The base ratio at which this token will be
/// compensated on soft liquidation.
/// @return The liquidation incentive curve length between soft
/// liquidation to hard liquidation, in `WAD`. e.g. 5% base
/// incentive with 8% curve length results in 13% liquidation
/// incentive on hard liquidation.
/// @return The minimum possible liquidation incentive for during an
/// auction, in `WAD`.
/// @return The maximum possible liquidation incentive for during an
/// auction, in `WAD`.
/// @return Maximum % that a liquidator can repay when soft
/// liquidating an account, in `WAD`.
/// @return Curve length between soft liquidation and hard liquidation,
/// should be equal to 100% - `closeFactorBase`, in `WAD`.
/// @return The minimum possible close factor for during an auction,
/// in `WAD`.
/// @return The maximum possible close factor for during an auction,
/// in `WAD`.
function liquidationConfig(address cToken) external view returns (
uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
);
/// @notice Enables an auction-based liquidation, potentially with a dynamic
/// close factor and liquidation penalty values in transient storage.
/// @dev Transient storage enforces any liquidator outside auction-based
/// liquidations uses the default risk parameters.
/// @param cToken The Curvance token to configure liquidations for during
/// an auction-based liquidation.
/// @param incentive The auction liquidation incentive value, in `BPS`.
/// @param closeFactor The auction close factor value, in `BPS`.
function setTransientLiquidationConfig(
address cToken,
uint256 incentive,
uint256 closeFactor
) external;
/// @notice Called from the AuctionManager as a post hook after liquidations
/// are tried to enable all collateral to be liquidated outside
/// an Auction tx.
/// @notice Resets the liquidation risk parameters in transient storage to
/// zero.
/// @dev This is redundant since the transient values will be reset after
/// the liquidation transaction, but can be useful during meta calls
/// with multiple liquidations during a single transaction.
function resetTransientLiquidationConfig() external;
/// @notice Checks if the account should be allowed to mint tokens
/// in the given market.
/// @param cToken The token to verify mints against.
function canMint(address cToken) external;
/// @notice Checks if the account should be allowed to collateralize
/// their shares of the given market.
/// Prunes unused positions in `account` data.
/// @dev May emit a {PositionUpdated} event.
/// @param cToken The token to verify collateralization of.
/// @param account The account which would collateralize the asset.
/// @param newNetCollateral The amount of shares that would be
/// collateralized in total if allowed.
function canCollateralize(
address cToken,
address account,
uint256 newNetCollateral
) external;
/// @notice Checks if the account should be allowed to redeem tokens
/// in the given market, and then redeems.
/// @dev This can only be called by the cToken itself.
/// @param cToken The token to verify the redemption against.
/// @param shares The number of cToken shares to redeem for the
/// underlying asset in the market.
/// @param account The account which would redeem `shares`.
/// @param balanceOf The current cToken share balance of `account`.
/// @param collateralPosted The current cToken shares posted as
/// collateral by `account`.
/// @param forceRedeemCollateral Whether the collateral should be always
/// reduced.
function canRedeemWithCollateralRemoval(
address cToken,
uint256 shares,
address account,
uint256 balanceOf,
uint256 collateralPosted,
bool forceRedeemCollateral
) external returns (uint256);
/// @notice Checks if the account should be allowed to borrow
/// the underlying asset of the given market.
/// Prunes unused positions in `account` data.
/// @dev May emit a {PositionUpdated} event.
/// @param cToken The token to verify borrowability of.
/// @param assets The amount of underlying assets `account` would borrow.
/// @param account The account which would borrow the asset.
/// @param newNetDebt The amount of assets that would be
/// outstanding debt in total if allowed.
function canBorrow(
address cToken,
uint256 assets,
address account,
uint256 newNetDebt
) external;
/// @notice Checks if the account should be allowed to borrow
/// the underlying asset of the given market,
/// and notifies the market of the borrow.
/// @dev This can only be called by the market itself.
/// @param cToken The market to verify the borrow against.
/// @param assets The amount of underlying assets `account` would borrow.
/// @param account The account which would borrow the asset.
/// @param newNetDebt The amount of assets that would be
/// outstanding debt in total if allowed.
function canBorrowWithNotify(
address cToken,
uint256 assets,
address account,
uint256 newNetDebt
) external;
/// @notice Checks if the account should be allowed to repay a borrow
/// in the given market, may clean up positions.
/// @param cToken The Curvance token to verify the repayment of.
/// @param newNetDebt The new debt amount owed by `account` after
/// repayment.
/// @param debtAsset The debt asset being repaid to `cToken`.
/// @param decimals The decimals that `debtToken` is measured in.
/// @param account The account who will have their loan repaid.
function canRepayWithReview(
address cToken,
uint256 newNetDebt,
address debtAsset,
uint256 decimals,
address account
) external;
/// @notice Checks if the liquidation should be allowed to occur,
/// and returns how many collateralized shares should be seized
/// on liquidation.
/// @param debtAmounts The amounts of outstanding debt the liquidator
/// wishes to repay, in underlying assets, empty if
/// intention is to liquidate maximum amount possible
/// for each account.
/// @param liquidator The address of the account trying to liquidate
/// `accounts`.
/// @param accounts The addresses of the accounts to be liquidated.
/// @param action A LiqAction struct containing:
/// collateralToken The token which is used as collateral
/// by `account` and may be seized.
/// debtToken The token to potentially repay which has
/// outstanding debt by `account`.
/// numAccounts The number of accounts to be, potentially,
/// liquidated.
/// liquidateExact Whether the liquidator desires a
/// specific liquidation amount.
/// collateralLiquidated Empty variable slot to store how
/// much `collateralToken` will be
/// seized as part of a particular
/// liquidation.
/// debtRepaid Empty variable slot to store how much
/// `debtToken` will be repaid as part of a
/// particular liquidation.
/// badDebt Empty variable slot to store how much bad debt
/// will be realized as part of a particular
/// liquidation.
/// @return result A LiqResult struct containing:
/// liquidatedShares An array containing the collateral
/// amounts to liquidate from
/// `accounts`.
/// debtRepaid The total amount of debt to repay from
/// `accounts`.
/// badDebtRealized The total amount of debt to realize as
/// losses for lenders inside this market.
/// @return An array containing the debt amounts to repay from
/// `accounts`, in assets.
function canLiquidate(
uint256[] memory debtAmounts,
address liquidator,
address[] calldata accounts,
IMarketManager.LiqAction memory action
) external returns (LiqResult memory, uint256[] memory);
/// @notice Checks if the seizing of `collateralToken` by repayment of
/// `debtToken` should be allowed.
/// @param collateralToken The Curvance token which was used as collateral
/// and will be seized.
/// @param debtToken The Curvance token which has outstanding debt to and
/// would be repaid during `collateralToken` seizure.
function canSeize(address collateralToken, address debtToken) external;
/// @notice Checks if the account should be allowed to transfer collateral
/// tokens in the given market.
/// @param cToken The Curvance token to verify the transfer of.
/// @param shares The amount of `cToken` to transfer.
/// @param account The account which will transfer `shares`.
/// @param balanceOf The current balance that `account` has of `cToken`
/// shares.
/// @param collateralPosted The amount of `cToken` shares posted as
/// collateral by `account`.
/// @param isCollateral Boolean indicating whether the token is currently
/// being used as collateral.
function canTransfer(
address cToken,
uint256 shares,
address account,
uint256 balanceOf,
uint256 collateralPosted,
bool isCollateral
) external returns (uint256);
/// @notice Updates `account` cooldownTimestamp to the current block
/// timestamp.
/// @dev The caller must be a listed cToken in the `markets` mapping.
/// @param cToken The address of the token that the account is borrowing.
/// @param account The address of the account that has just borrowed.
function notifyBorrow(address cToken, address account) external;
/// @notice A list of all tokens inside this market for
/// offchain querying.
function queryTokensListed() external view returns (address[] memory);
/// @notice Returns whether `cToken` is listed in the lending market.
/// @param cToken market token address.
function isListed(address cToken) external view returns (bool);
/// @notice The total amount of `cToken` that can be posted as collateral,
/// in shares.
function collateralCaps(address cToken) external view returns (uint256);
/// @notice The total amount of `cToken` underlying that can be borrowed,
/// in assets.
function debtCaps(address cToken) external view returns (uint256);
/// @notice Returns whether `addressToCheck` is an approved position
/// manager or not.
/// @param addressToCheck Address to check for position management
/// authority.
function isPositionManager(
address addressToCheck
) external view returns (bool);
/// @notice Returns the assets an account has entered.
/// @param account The address of the account to pull assets for.
/// @return A dynamic list with the assets `account` has entered.
function assetsOf(
address account
) external view returns (address[] memory);
/// @notice Determine `account`'s current status between collateral,
/// debt, and additional liquidity.
/// @param account The account to determine liquidity for.
/// @return The current total collateral amount of `account`.
/// @return The maximum debt amount of `account` can take out with
/// their current collateral.
/// @return The current total borrow amount of `account`.
function statusOf(
address account
) external returns (uint256, uint256, uint256);
}
// contracts/interfaces/IMulticallChecker.sol
interface IMulticallChecker {
function checkCalldata(
address caller,
address target,
bytes memory data
) external;
}
// contracts/interfaces/IPluginDelegable.sol
interface IPluginDelegable {
/// @notice Returns whether a user or contract has the ability to act
/// on behalf of an account.
/// @param user The address to check whether `delegate` has delegation
/// permissions.
/// @param delegate The address that will be approved or restricted
/// from delegated actions on behalf of the caller.
/// @return result Indicates whether `delegate` is an approved delegate or
/// not of `user`, true = disabled, false = not disabled.
function isDelegate(
address user,
address delegate
) external view returns (bool result);
/// @notice Approves or restricts `delegate`'s authority to operate
/// on the caller's behalf.
/// @dev NOTE: Be careful who you approve here!
/// They can delay actions such as asset redemption through repeated
/// denial of service.
/// Emits a {DelegateApproval} event.
/// @param delegate The address that will be approved or restricted
/// from delegated actions on behalf of the caller.
/// @param isApproved Whether `delegate` is being approved or restricted
/// of authority to operate on behalf of caller.
function setDelegateApproval(address delegate, bool isApproved) external;
}
// contracts/libraries/LowLevelCallsHelper.sol
library LowLevelCallsHelper {
/// ERRORS ///
error LowLevelCallsHelper__InsufficientBalance();
error LowLevelCallsHelper__CallFailed();
/// INTERNAL FUNCTIONS ///
/// @notice Executes a low level .call() and validates that execution
/// was safely performed.
/// @dev Bubbles up errors and reverts if anything along the execution
/// path failed or was a red flag.
/// @param target The target contract address to execute .call() at.
/// @param data The bytecode data to attach to the .call() execution
/// including the function signature hash and function call
/// parameters.
function _call(
address target,
bytes memory data
) internal returns (bytes memory) {
(bool success, bytes memory returnData) = target.call{value: 0}(data);
return _verifyResult(target, success, returnData);
}
/// @notice Executes a low level .call(), with attached native token
/// and validates that execution was safely performed.
/// @dev Bubbles up errors and reverts if anything along the execution
/// path failed or was a red flag.
/// @param target The target contract address to execute .call() at.
/// @param data The bytecode data to attach to the .call() execution
/// including the function signature hash and function call
/// parameters.
/// @param value The amount of native token to attach to the low level
/// call.
function _callWithNative(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
if (address(this).balance < value) {
revert LowLevelCallsHelper__InsufficientBalance();
}
(bool success, bytes memory returnData) = target.call{
value: value
}(data);
return _verifyResult(target, success, returnData);
}
/// @notice Executes a low level .delegatecall() and validates that
/// execution was safely performed.
/// @dev Bubbles up errors and reverts if anything along the execution
/// path failed or was a red flag.
/// @param target The target contract address to execute .delegatecall()
/// at.
/// @param data The bytecode data to attach to the .call() execution
/// including the function signature hash and function call
/// parameters.
function _delegateCall(
address target,
bytes memory data
) internal returns (bytes memory) {
(bool success, bytes memory returnData) = target.delegatecall(data);
return _verifyResult(target, success, returnData);
}
/// @dev Validates whether the low level call or delegate call was
/// successful and reverts in cases of bubbled up revert messages
/// or if `target` was not actually a contract.
function _verifyResult(
address target,
bool success,
bytes memory returnData
) internal view returns (bytes memory) {
_propagateError(success, returnData);
// If the call was successful but there was no return data we need
// to make sure a contract was actually called as expected.
if (returnData.length == 0 && target.code.length == 0) {
revert LowLevelCallsHelper__CallFailed();
}
return returnData;
}
/// @dev Propagates an error message, if necessary.
/// @param success If transaction was successful.
/// @param resultData The transaction result data.
function _propagateError(
bool success,
bytes memory resultData
) internal pure {
if (!success) {
if (resultData.length == 0) {
revert LowLevelCallsHelper__CallFailed();
}
// Bubble up error if there was one given.
assembly {
revert(add(32, resultData), mload(resultData))
}
}
}
}
// contracts/libraries/ReentrancyGuardTransient.sol
/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuardTransient.sol)
/// @dev Mai: Edited to always use transient storage.
abstract contract ReentrancyGuard {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unauthorized reentrant call.
error Reentrancy();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to: `uint32(bytes4(keccak256("Reentrancy()"))) | 1 << 71`.
/// 9 bytes is large enough to avoid collisions in practice,
/// but not too large to result in excessive bytecode bloat.
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x8000000000ab143c06;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* REENTRANCY GUARD */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Guards a function from reentrancy.
modifier nonReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if tload(_REENTRANCY_GUARD_SLOT) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
tstore(_REENTRANCY_GUARD_SLOT, address())
}
_;
/// @solidity memory-safe-assembly
assembly {
tstore(_REENTRANCY_GUARD_SLOT, 0)
}
}
/// @dev Guards a view function from read-only reentrancy.
modifier nonReadReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if tload(_REENTRANCY_GUARD_SLOT) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
_;
}
}
// contracts/libraries/external/SafeTransferLib.sol
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for
/// the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul(
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}
// contracts/libraries/external/ERC165.sol
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// contracts/libraries/external/ERC165Checker.sol
// @author Modified from OpenZeppelin Contracts (utils/introspection/ERC165Checker.sol)
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(
account,
type(IERC165).interfaceId
) &&
!supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(
address account,
bytes4 interfaceId
) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return
supportsERC165(account) &&
supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(
address account,
bytes4 interfaceId
) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(
IERC165.supportsInterface,
(interfaceId)
);
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(
30000,
account,
add(encodedParams, 0x20),
mload(encodedParams),
0x00,
0x20
)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}
// contracts/libraries/CentralRegistryLib.sol
/// @title Curvance Central Registry Validation Library
/// @notice For validating that Central Registry is configured properly
/// on launch.
library CentralRegistryLib {
/// ERRORS ///
error CentralRegistryLib__InvalidCentralRegistry();
/// INTERNAL FUNCTIONS ///
/// @notice Validates that `cr` is the Protocol Central Registry.
/// @param cr The proposed Protocol Central Registry.
function _isCentralRegistry(ICentralRegistry cr) internal view {
if (
!ERC165Checker.supportsInterface(
address(cr),
type(ICentralRegistry).interfaceId
)
) {
revert CentralRegistryLib__InvalidCentralRegistry();
}
}
}
// contracts/libraries/external/ERC4626.sol
/// @notice Simple ERC4626 tokenized Vault implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC4626.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The default underlying decimals.
uint8 internal constant _DEFAULT_UNDERLYING_DECIMALS = 18;
/// @dev The default decimals offset.
uint8 internal constant _DEFAULT_DECIMALS_OFFSET = 0;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cannot deposit more than the max limit.
error DepositMoreThanMax();
/// @dev Cannot mint more than the max limit.
error MintMoreThanMax();
/// @dev Cannot withdraw more than the max limit.
error WithdrawMoreThanMax();
/// @dev Cannot redeem more than the max limit.
error RedeemMoreThanMax();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted during a mint call or deposit call.
event Deposit(address indexed by, address indexed owner, uint256 assets, uint256 shares);
/// @dev Emitted during a withdraw call or redeem call.
event Withdraw(
address indexed by,
address indexed to,
address indexed owner,
uint256 assets,
uint256 shares
);
/// @dev `keccak256(bytes("Deposit(address,address,uint256,uint256)"))`.
uint256 private constant _DEPOSIT_EVENT_SIGNATURE =
0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7;
/// @dev `keccak256(bytes("Withdraw(address,address,address,uint256,uint256)"))`.
uint256 private constant _WITHDRAW_EVENT_SIGNATURE =
0xfbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC4626 CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev To be overridden to return the address of the underlying asset.
///
/// - MUST be an ERC20 token contract.
/// - MUST NOT revert.
function asset() public view virtual returns (address);
/// @dev To be overridden to return the number of decimals of the underlying asset.
/// Default: 18.
///
/// - MUST NOT revert.
function _underlyingDecimals() internal view virtual returns (uint8) {
return _DEFAULT_UNDERLYING_DECIMALS;
}
/// @dev Override to return a non-zero value to make the inflation attack even more unfeasible.
/// Only used when {_useVirtualShares} returns true.
/// Default: 0.
///
/// - MUST NOT revert.
function _decimalsOffset() internal view virtual returns (uint8) {
return _DEFAULT_DECIMALS_OFFSET;
}
/// @dev Returns whether virtual shares will be used to mitigate the inflation attack.
/// See: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706
/// Override to return true or false.
/// Default: true.
///
/// - MUST NOT revert.
function _useVirtualShares() internal view virtual returns (bool) {
return true;
}
/// @dev Returns the decimals places of the token.
///
/// - MUST NOT revert.
function decimals() public view virtual override(ERC20) returns (uint8) {
if (!_useVirtualShares()) return _underlyingDecimals();
return _underlyingDecimals() + _decimalsOffset();
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ASSET DECIMALS GETTER HELPER */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Helper function to get the decimals of the underlying asset.
/// Useful for setting the return value of `_underlyingDecimals` during initialization.
/// If the retrieval succeeds, `success` will be true, and `result` will hold the result.
/// Otherwise, `success` will be false, and `result` will be zero.
///
/// Example usage:
/// ```
/// (bool success, uint8 result) = _tryGetAssetDecimals(underlying);
/// _decimals = success ? result : _DEFAULT_UNDERLYING_DECIMALS;
/// ```
function _tryGetAssetDecimals(address underlying)
internal
view
returns (bool success, uint8 result)
{
/// @solidity memory-safe-assembly
assembly {
// Store the function selector of `decimals()`.
mstore(0x00, 0x313ce567)
// Arguments are evaluated last to first.
success :=
and(
// Returned value is less than 256, at left-padded to 32 bytes.
and(lt(mload(0x00), 0x100), gt(returndatasize(), 0x1f)),
// The staticcall succeeds.
staticcall(gas(), underlying, 0x1c, 0x04, 0x00, 0x20)
)
result := mul(mload(0x00), success)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ACCOUNTING LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the total amount of the underlying asset managed by the Vault.
///
/// - SHOULD include any compounding that occurs from the yield.
/// - MUST be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT revert.
function totalAssets() public view virtual returns (uint256 assets) {
assets = SafeTransferLib.balanceOf(asset(), address(this));
}
/// @dev Returns the amount of shares that the Vault will exchange for the amount of
/// assets provided, in an ideal scenario where all conditions are met.
///
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, during the actual exchange.
/// - MUST NOT revert.
///
/// Note: This calculation MAY NOT reflect the "per-user" price-per-share, and instead
/// should reflect the "average-user's" price-per-share, i.e. what the average user should
/// expect to see when exchanging to and from.
function convertToShares(uint256 assets) public view virtual returns (uint256 shares) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return _eitherIsZero(assets, supply)
? _initialConvertToShares(assets)
: FixedPointMathLib.fullMulDiv(assets, supply, totalAssets());
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDiv(assets, totalSupply() + 1, _inc(totalAssets()));
}
return FixedPointMathLib.fullMulDiv(assets, totalSupply() + 10 ** o, _inc(totalAssets()));
}
/// @dev Returns the amount of assets that the Vault will exchange for the amount of
/// shares provided, in an ideal scenario where all conditions are met.
///
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, during the actual exchange.
/// - MUST NOT revert.
///
/// Note: This calculation MAY NOT reflect the "per-user" price-per-share, and instead
/// should reflect the "average-user's" price-per-share, i.e. what the average user should
/// expect to see when exchanging to and from.
function convertToAssets(uint256 shares) public view virtual returns (uint256 assets) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return supply == uint256(0)
? _initialConvertToAssets(shares)
: FixedPointMathLib.fullMulDiv(shares, totalAssets(), supply);
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDiv(shares, totalAssets() + 1, _inc(totalSupply()));
}
return FixedPointMathLib.fullMulDiv(shares, totalAssets() + 1, totalSupply() + 10 ** o);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their deposit
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no more than the exact amount of Vault shares that
/// will be minted in a deposit call in the same transaction, i.e. deposit should
/// return the same or more shares as `previewDeposit` if call in the same transaction.
/// - MUST NOT account for deposit limits like those returned from `maxDeposit` and should
/// always act as if the deposit will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToShares` and `previewDeposit` SHOULD
/// be considered slippage in share price or some other type of condition, meaning
/// the depositor will lose assets by depositing.
function previewDeposit(uint256 assets) public view virtual returns (uint256 shares) {
shares = convertToShares(assets);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their mint
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no fewer than the exact amount of assets that
/// will be deposited in a mint call in the same transaction, i.e. mint should
/// return the same or fewer assets as `previewMint` if called in the same transaction.
/// - MUST NOT account for mint limits like those returned from `maxMint` and should
/// always act as if the mint will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToAssets` and `previewMint` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by minting.
function previewMint(uint256 shares) public view virtual returns (uint256 assets) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return supply == uint256(0)
? _initialConvertToAssets(shares)
: FixedPointMathLib.fullMulDivUp(shares, totalAssets(), supply);
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDivUp(shares, totalAssets() + 1, _inc(totalSupply()));
}
return FixedPointMathLib.fullMulDivUp(shares, totalAssets() + 1, totalSupply() + 10 ** o);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal
/// at the current block, given the current on-chain conditions.
///
/// - MUST return as close to and no fewer than the exact amount of Vault shares that
/// will be burned in a withdraw call in the same transaction, i.e. withdraw should
/// return the same or fewer shares as `previewWithdraw` if call in the same transaction.
/// - MUST NOT account for withdrawal limits like those returned from `maxWithdraw` and should
/// always act as if the withdrawal will be accepted, regardless of share balance, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToShares` and `previewWithdraw` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by depositing.
function previewWithdraw(uint256 assets) public view virtual returns (uint256 shares) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return _eitherIsZero(assets, supply)
? _initialConvertToShares(assets)
: FixedPointMathLib.fullMulDivUp(assets, supply, totalAssets());
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDivUp(assets, totalSupply() + 1, _inc(totalAssets()));
}
return FixedPointMathLib.fullMulDivUp(assets, totalSupply() + 10 ** o, _inc(totalAssets()));
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their redemption
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no more than the exact amount of assets that
/// will be withdrawn in a redeem call in the same transaction, i.e. redeem should
/// return the same or more assets as `previewRedeem` if called in the same transaction.
/// - MUST NOT account for redemption limits like those returned from `maxRedeem` and should
/// always act as if the redemption will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of this.
/// - MUST NOT revert.
///
/// Note: Any unfavorable discrepancy between `convertToAssets` and `previewRedeem` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by depositing.
function previewRedeem(uint256 shares) public view virtual returns (uint256 assets) {
assets = convertToAssets(shares);
}
/// @dev Private helper to return if either value is zero.
function _eitherIsZero(uint256 a, uint256 b) private pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := or(iszero(a), iszero(b))
}
}
/// @dev Private helper to return `x + 1` without the overflow check.
/// Used for computing the denominator input to `FixedPointMathLib.fullMulDiv(a, b, x + 1)`.
/// When `x == type(uint256).max`, we get `x + 1 == 0` (mod 2**256 - 1),
/// and `FixedPointMathLib.fullMulDiv` will revert as the denominator is zero.
function _inc(uint256 x) private pure returns (uint256) {
unchecked {
return x + 1;
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DEPOSIT / WITHDRAWAL LIMIT LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the maximum amount of the underlying asset that can be deposited
/// into the Vault for `to`, via a deposit call.
///
/// - MUST return a limited value if `to` is subject to some deposit limit.
/// - MUST return `2**256-1` if there is no maximum limit.
/// - MUST NOT revert.
function maxDeposit(address to) public view virtual returns (uint256 maxAssets) {
to = to; // Silence unused variable warning.
maxAssets = type(uint256).max;
}
/// @dev Returns the maximum amount of the Vault shares that can be minter for `to`,
/// via a mint call.
///
/// - MUST return a limited value if `to` is subject to some mint limit.
/// - MUST return `2**256-1` if there is no maximum limit.
/// - MUST NOT revert.
function maxMint(address to) public view virtual returns (uint256 maxShares) {
to = to; // Silence unused variable warning.
maxShares = type(uint256).max;
}
/// @dev Returns the maximum amount of the underlying asset that can be withdrawn
/// from the `owner`'s balance in the Vault, via a withdraw call.
///
/// - MUST return a limited value if `owner` is subject to some withdrawal limit or timelock.
/// - MUST NOT revert.
function maxWithdraw(address owner) public view virtual returns (uint256 maxAssets) {
maxAssets = convertToAssets(balanceOf(owner));
}
/// @dev Returns the maximum amount of Vault shares that can be redeemed
/// from the `owner`'s balance in the Vault, via a redeem call.
///
/// - MUST return a limited value if `owner` is subject to some withdrawal limit or timelock.
/// - MUST return `balanceOf(owner)` otherwise.
/// - MUST NOT revert.
function maxRedeem(address owner) public view virtual returns (uint256 maxShares) {
maxShares = balanceOf(owner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DEPOSIT / WITHDRAWAL LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `shares` Vault shares to `to` by depositing exactly `assets`
/// of underlying tokens.
///
/// - MUST emit the {Deposit} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the deposit execution, and are accounted for during deposit.
/// - MUST revert if all of `assets` cannot be deposited, such as due to deposit limit,
/// slippage, insufficient approval, etc.
///
/// Note: Most implementations will require pre-approval of the Vault with the
/// Vault's underlying `asset` token.
function deposit(uint256 assets, address to) public virtual returns (uint256 shares) {
if (assets > maxDeposit(to)) _revert(0xb3c61a83); // `DepositMoreThanMax()`.
shares = previewDeposit(assets);
_deposit(msg.sender, to, assets, shares);
}
/// @dev Mints exactly `shares` Vault shares to `to` by depositing `assets`
/// of underlying tokens.
///
/// - MUST emit the {Deposit} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the mint execution, and are accounted for during mint.
/// - MUST revert if all of `shares` cannot be deposited, such as due to deposit limit,
/// slippage, insufficient approval, etc.
///
/// Note: Most implementations will require pre-approval of the Vault with the
/// Vault's underlying `asset` token.
function mint(uint256 shares, address to) public virtual returns (uint256 assets) {
if (shares > maxMint(to)) _revert(0x6a695959); // `MintMoreThanMax()`.
assets = previewMint(shares);
_deposit(msg.sender, to, assets, shares);
}
/// @dev Burns `shares` from `owner` and sends exactly `assets` of underlying tokens to `to`.
///
/// - MUST emit the {Withdraw} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the withdraw execution, and are accounted for during withdraw.
/// - MUST revert if all of `assets` cannot be withdrawn, such as due to withdrawal limit,
/// slippage, insufficient balance, etc.
///
/// Note: Some implementations will require pre-requesting to the Vault before a withdrawal
/// may be performed. Those methods should be performed separately.
function withdraw(uint256 assets, address to, address owner)
public
virtual
returns (uint256 shares)
{
if (assets > maxWithdraw(owner)) _revert(0x936941fc); // `WithdrawMoreThanMax()`.
shares = previewWithdraw(assets);
_withdraw(msg.sender, to, owner, assets, shares);
}
/// @dev Burns exactly `shares` from `owner` and sends `assets` of underlying tokens to `to`.
///
/// - MUST emit the {Withdraw} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the redeem execution, and are accounted for during redeem.
/// - MUST revert if all of shares cannot be redeemed, such as due to withdrawal limit,
/// slippage, insufficient balance, etc.
///
/// Note: Some implementations will require pre-requesting to the Vault before a redeem
/// may be performed. Those methods should be performed separately.
function redeem(uint256 shares, address to, address owner)
public
virtual
returns (uint256 assets)
{
if (shares > maxRedeem(owner)) _revert(0x4656425a); // `RedeemMoreThanMax()`.
assets = previewRedeem(shares);
_withdraw(msg.sender, to, owner, assets, shares);
}
/// @dev Internal helper for reverting efficiently.
function _revert(uint256 s) internal pure {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, s)
revert(0x1c, 0x04)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For deposits and mints.
///
/// Emits a {Deposit} event.
function _deposit(address by, address to, uint256 assets, uint256 shares) internal virtual {
SafeTransferLib.safeTransferFrom(asset(), by, address(this), assets);
_mint(to, shares);
/// @solidity memory-safe-assembly
assembly {
// Emit the {Deposit} event.
mstore(0x00, assets)
mstore(0x20, shares)
let m := shr(96, not(0))
log3(0x00, 0x40, _DEPOSIT_EVENT_SIGNATURE, and(m, by), and(m, to))
}
_afterDeposit(assets, shares);
}
/// @dev For withdrawals and redemptions.
///
/// Emits a {Withdraw} event.
function _withdraw(address by, address to, address owner, uint256 assets, uint256 shares)
internal
virtual
{
if (by != owner) _spendAllowance(owner, by, shares);
_beforeWithdraw(assets, shares);
_burn(owner, shares);
SafeTransferLib.safeTransfer(asset(), to, assets);
/// @solidity memory-safe-assembly
assembly {
// Emit the {Withdraw} event.
mstore(0x00, assets)
mstore(0x20, shares)
let m := shr(96, not(0))
log4(0x00, 0x40, _WITHDRAW_EVENT_SIGNATURE, and(m, by), and(m, to), and(m, owner))
}
}
/// @dev Internal conversion function (from assets to shares) to apply when the Vault is empty.
/// Only used when {_useVirtualShares} returns false.
///
/// Note: Make sure to keep this function consistent with {_initialConvertToAssets}
/// when overriding it.
function _initialConvertToShares(uint256 assets)
internal
view
virtual
returns (uint256 shares)
{
shares = assets;
}
/// @dev Internal conversion function (from shares to assets) to apply when the Vault is empty.
/// Only used when {_useVirtualShares} returns false.
///
/// Note: Make sure to keep this function consistent with {_initialConvertToShares}
/// when overriding it.
function _initialConvertToAssets(uint256 shares)
internal
view
virtual
returns (uint256 assets)
{
assets = shares;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any withdrawal or redemption.
function _beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}
/// @dev Hook that is called after any deposit or mint.
function _afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}
// contracts/libraries/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/PluginDelegable.sol
/// @title Curvance Plugin Delegation Manager.
/// @notice Facilitates delegated actions on behalf of a user inside Curvance.
/// @dev `PluginDelegable` allows the Curvance Protocol to be a modular system
/// that plugins can be built on top of. By delegating action authority
/// to an address or addresses users can utilize potential third-party
/// features such as limit orders, crosschain actions, reward auto
/// compounding, chained (multiple sequential) actions, etc.
abstract contract PluginDelegable is IPluginDelegable {
/// CONSTANTS ///
/// @notice Curvance DAO Hub.
ICentralRegistry public immutable centralRegistry;
/// STORAGE ///
/// @notice Status of whether a user or contract has the ability to act
/// on behalf of an account.
/// @dev Account address => approval index => Spender address => Can act
/// on behalf of account.
mapping(address => mapping(uint256 => mapping(address => bool)))
internal _isDelegate;
/// EVENTS ///
event DelegateApproval(
address indexed owner,
address indexed delegate,
uint256 approvalIndex,
bool isApproved
);
/// ERRORS ///
error PluginDelegable__Unauthorized();
error PluginDelegable__DelegatingDisabled();
error PluginDelegable_InvalidParameter();
/// CONSTRUCTOR ///
/// @param cr The address of the Central Registry contract.
constructor(ICentralRegistry cr) {
CentralRegistryLib._isCentralRegistry(cr);
centralRegistry = cr;
}
/// EXTERNAL FUNCTIONS ///
/// @notice Approves or restricts `delegate`'s authority to operate
/// on the caller's behalf.
/// @dev NOTE: Be careful who you approve here!
/// They can delay actions such as asset redemption through repeated
/// denial of service.
/// Emits a {DelegateApproval} event.
/// @param delegate The address that will be approved or restricted
/// from delegated actions on behalf of the caller.
/// @param isApproved Whether `delegate` is being approved or restricted
/// of authority to operate on behalf of caller.
function setDelegateApproval(address delegate, bool isApproved) external {
if (delegate == msg.sender) {
revert PluginDelegable_InvalidParameter();
}
// Validate that new delegation configuration is current allowed for
// the caller.
if (centralRegistry.checkNewDelegationDisabled(msg.sender)) {
revert PluginDelegable__DelegatingDisabled();
}
uint256 currentIndex = centralRegistry.userApprovalIndex(msg.sender);
_isDelegate[msg.sender][currentIndex][delegate] = isApproved;
emit DelegateApproval(msg.sender, delegate, currentIndex, isApproved);
}
/// @notice Returns `user`'s current approval index value.
/// @dev The approval index is a way to revoke approval on all tokens,
/// and features at once if a malicious delegation was allowed by
/// `user`.
/// @param user The user to check delegated approval index for.
/// @return result The `user`'s current approval index value.
function userApprovalIndex(
address user
) external view returns (uint256 result) {
result = centralRegistry.userApprovalIndex(user);
}
/// @notice Returns whether `delegate` has the ability to act on behalf of
/// `user`.
/// @param user The address to check whether `delegate` has delegation
/// permissions for.
/// @param delegate The address to check delegation permissions of `user`.
/// @return result Indicates whether `delegate` is an approved delegate or
/// not of `user`, true = is a delegate, false = is not
/// a delegate.
function isDelegate(
address user,
address delegate
) external view returns (bool result) {
result = _isDelegate[user][centralRegistry
.userApprovalIndex(user)][delegate];
}
/// @notice Returns whether a user has delegation disabled.
/// @dev This is not a silver bullet for phishing attacks, but, adds
/// an additional wall of defense.
/// @param user The user to check delegation status for.
/// @return result Indicates whether `user` has delegation disabled
/// or not, true = disabled, false = not disabled.
function checkNewDelegationDisabled(
address user
) external view returns (bool result) {
result = centralRegistry.checkNewDelegationDisabled(user);
}
/// INTERNAL FUNCTIONS ///
/// @notice Checks whether `delegate` has the ability to act on behalf of
/// `user`, reverts if they do not.
/// @param user The address to check whether `delegate` has delegation
/// permissions for.
/// @param delegate The address to check delegation permissions of `user`.
function _checkDelegate(address user, address delegate) internal view {
if (
!_isDelegate[user][centralRegistry
.userApprovalIndex(user)][delegate]
) {
revert PluginDelegable__Unauthorized();
}
}
}
// contracts/libraries/CommonLib.sol
/// @title Curvance Common Library
/// @notice A utility library for common functions used throughout the
/// Curvance Protocol.
library CommonLib {
/// @notice Returns whether `tokenA` matches `tokenB` or not.
/// @param tokenA The first token address to compare.
/// @param tokenB The second token address to compare.
/// @return Whether `tokenA` matches `tokenB` or not.
function _isMatchingToken(
address tokenA,
address tokenB
) internal pure returns (bool) {
if (tokenA == tokenB) {
return true;
}
if (_isNative(tokenA) && _isNative(tokenB)) {
return true;
}
return false;
}
/// @notice Returns whether `token` is referring to network gas token
/// or not.
/// @param token The address to review.
/// @return result Whether `token` is referring to network gas token or
/// not.
function _isNative(address token) internal pure returns (bool result) {
result = token == address(0) ||
token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
}
/// @notice Returns balance of `token` for this contract.
/// @param token The token address to query balance of.
/// @return b The balance of `token` inside address(this).
function _balanceOf(address token) internal view returns (uint256 b) {
b = _isNative(token) ? address(this).balance :
IERC20(token).balanceOf(address(this));
}
/// @notice Returns the Oracle Manager in interface form from `cr`.
/// @param cr The address of the Protocol Central Registry.
/// @return oracleManager The Oracle Manager in interface form.
function _oracleManager(
ICentralRegistry cr
) internal view returns (IOracleManager oracleManager) {
oracleManager = IOracleManager(cr.oracleManager());
}
}
// contracts/interfaces/IBorrowableCToken.sol
interface IBorrowableCToken {
/// ICToken GENERIC FUNCTIONS ///
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @param by The account initializing deposits.
function initializeDeposits(address by) external returns (bool);
/// @notice Returns the decimals of the cToken.
/// @dev We pull directly from underlying incase its a proxy contract,
/// and changes decimals on us.
/// @return The number of decimals for this cToken,
/// matching the underlying token.
function decimals() external view returns (uint8);
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return Whether this token is borrowable or not.
function isBorrowable() external view returns (bool);
/// @notice The token balance of an account.
/// @dev Account address => account token balance.
/// @param account The address of the account to query token balance for.
function balanceOf(address account) external view returns (uint256);
/// @notice Returns the address of the underlying asset.
/// @return The address of the underlying asset.
function asset() external view returns (address);
/// @notice Returns the current vesting yield information.
/// @return vestingRate % per second in `asset()`.
/// @return vestingEnd When the current vesting period ends and interest
/// rates paid will update.
/// @return lastVestingClaim Last time pending vested yield was claimed.
/// @return debtIndex The current market debt index.
function getYieldInformation() external view returns (
uint256 vestingRate,
uint256 vestingEnd,
uint256 lastVestingClaim,
uint256 debtIndex
);
/// @notice Get a snapshot of `account` data in this Curvance token.
/// @dev Used by marketManager to more efficiently perform
/// liquidity checks.
/// NOTE: Does not accrue pending interest as part of the call.
/// @param account The address of the account to snapshot.
/// @return The account snapshot of `account`.
function getSnapshot(
address account
) external view returns (AccountSnapshot memory);
/// @notice Total number of cTokens in circulation.
function totalSupply() external view returns (uint256);
/// @notice Returns the total amount of assets held by the market.
/// @return The total amount of assets held by the market.
function totalAssets() external view returns (uint256);
/// @notice Address of the Market Manager linked to this contract.
function marketManager() external view returns (IMarketManager);
/// @notice Returns the amount of assets that would be exchanged
/// by the vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @return The number of assets a user would receive for converting
/// `shares`.
function convertToAssets(uint256 shares) external view returns (uint256);
/// @notice Returns share -> asset exchange rate, in `WAD`.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
function exchangeRate() external view returns (uint256);
/// @notice Executes multiple calls in a single transaction.
/// This can be used to update oracle prices before
/// a liquidity dependent action.
function multicall(
Multicall.MulticallAction[] memory calls
) external returns (bytes[] memory results);
/// @notice Caller deposits `assets` into the market and `receiver`
/// receives shares.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function deposit(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev The caller must be depositing for themselves, or be managing
/// their position through a Position Manager contract.
/// If the caller is not approved to collateralize the function will
/// simply deposit assets on behalf of `receiver`.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateral(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev Requires that `receiver` approves the caller prior to
/// collateralize on their behalf.
/// NOTE: Be careful who you approve here!
/// They can delay redemption of assets through repeated
/// collateralization preventing withdrawal.
/// If the caller is not approved to collateralize the function will
/// simply deposit assets on behalf of `receiver`.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateralFor(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to be redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner`.
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares, sending assets to `receiver`.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Caller withdraws assets from the market and burns their
/// shares, on behalf of `owner`.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemCollateralFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param owner The owner address of assets to redeem.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function withdrawByPositionManager(
uint256 assets,
address owner,
IPositionManager.DeleverageAction memory action
) external;
/// @notice Amount of tokens that has been posted as collateral,
/// in shares.
function marketCollateralPosted() external view returns (uint256);
/// @notice Shares of this token that an account has posted as collateral.
/// @param account The address of the account to check collateral posted
/// of.
function collateralPosted(address account) external view returns (uint256);
/// @notice Transfers tokens from `account` to `liquidator`.
/// @dev Will fail unless called by a cToken during the process
/// of liquidation.
/// @param shares An array containing the number of cToken shares
/// to seize.
/// @param liquidator The account receiving seized cTokens.
/// @param accounts An array containing the accounts having
/// collateral seized.
function seize(
uint256[] calldata shares,
address liquidator,
address[] calldata accounts
) external;
/// @notice Allows users to simulate the effects of their deposit at
/// the current block.
/// @param assets The number of assets to preview a deposit call.
/// @return The shares received for depositing `assets`.
function previewDeposit(uint256 assets) external view returns (uint256);
/// IBorrowableCToken SPECIFIC FUNCTIONS ///
/// @notice Address of the current Dynamic IRM.
function IRM() external view returns (IDynamicIRM);
/// @notice Fee that goes to protocol for interested generated for
/// lenders, in `WAD`.
function interestFee() external view returns (uint256);
/// @notice Can accrue interest yield, configure next interest accrual
/// period, and updates vesting data, if needed.
/// @dev May emit a {RatesAdjusted} event.
function accrueIfNeeded() external;
/// @notice The amount of tokens that has been borrowed as debt,
/// in assets.
function marketOutstandingDebt() external view returns (uint256);
/// @notice Returns the current debt balance for `account`.
/// @dev Note: Pending interest is not applied in this calculation.
/// @param account The address whose debt balance should be calculated.
/// @return result The current outstanding debt balance of `account`.
function debtBalance(
address account
) external view returns (uint256 result);
/// @notice Updates pending interest and returns the current outstanding
/// debt owed by `account`.
/// @param account The address whose debt balance should be calculated.
/// @return result The current outstanding debt of `account`, with pending
/// interest applied.
function debtBalanceUpdated(
address account
) external returns (uint256 result);
/// @notice Updates pending interest and returns the up-to-date exchange
/// rate from the underlying to the BorrowableCToken.
/// @return result The share -> asset exchange rate, in `WAD`.
function exchangeRateUpdated() external returns (uint256);
/// @notice Used by a delegated user to borrow underlying tokens
/// from lenders, based on collateral posted inside this market
/// by `account`.
/// @dev Updates pending interest before executing the borrow.
/// NOTE: Be careful who you approve here!
/// Not only can they take borrowed funds, but, they can delay
/// repayment through repeated borrows preventing withdrawal.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account who will receive the borrowed assets.
/// @param owner The account who will have their assets borrowed
/// against.
function borrowFor(
uint256 assets,
address receiver,
address owner
) external;
/// @notice Used by a Position Manager contract to borrow assets from
/// lenders, based on collateralized shares by `account` to
/// perform a complex action.
/// @param assets The amount of the underlying assets to borrow.
/// @param owner The account address to borrow on behalf of.
/// @param action Instructions for a leverage action containing:
/// borrowableCToken Address of the borrowableCToken that
/// will be borrowed from and assets
/// swapped into `cToken` asset.
/// borrowAssets The amount borrowed from
/// `borrowableCToken`, in assets.
/// cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// swapAction Swap action instructions converting debt
/// asset into collateral asset to facilitate
/// leveraging.
/// auxData Optional auxiliary data for execution of a
/// leverage action.
function borrowForPositionManager(
uint256 assets,
address owner,
IPositionManager.LeverageAction memory action
) external;
/// @notice Repays underlying tokens to lenders, on behalf of `account`,
/// freeing up their collateral posted inside this market.
/// @dev Updates pending interest before executing the repay.
/// @param assets The amount to repay, or 0 for the full outstanding
/// amount.
/// @param owner The account address to repay on behalf of.
function repayFor(uint256 assets, address owner) external;
/// @notice Gets balance of this contract, in terms of the underlying.
/// @dev This excludes changes in underlying token balance by the
/// current transaction, if any.
/// @return The quantity of underlying tokens held by the market.
function assetsHeld() external view returns (uint256);
}
// contracts/interfaces/ICToken.sol
struct AccountSnapshot {
address asset;
address underlying;
uint8 decimals;
bool isCollateral;
uint256 collateralPosted;
uint256 debtBalance;
}
interface ICToken {
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @param by The account initializing deposits.
function initializeDeposits(address by) external returns (bool);
/// @notice Returns the decimals of the cToken.
/// @dev We pull directly from underlying incase its a proxy contract,
/// and changes decimals on us.
/// @return The number of decimals for this cToken,
/// matching the underlying token.
function decimals() external view returns (uint8);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return Whether this token is borrowable or not.
function isBorrowable() external view returns (bool);
/// @notice The token balance of an account.
/// @dev Account address => account token balance.
/// @param account The address of the account to query token balance for.
function balanceOf(address account) external view returns (uint256);
/// @notice Returns the address of the underlying asset.
/// @return The address of the underlying asset.
function asset() external view returns (address);
/// @notice Updates pending assets and returns a snapshot of the cToken
/// and `account` data.
/// @dev Used by marketManager to more efficiently perform
/// liquidity checks.
/// @return result The snapshot of the cToken and `account` data.
function getSnapshotUpdated(
address account
) external returns (AccountSnapshot memory result);
/// @notice Get a snapshot of `account` data in this Curvance token.
/// @dev NOTE: Does not accrue pending assets as part of the call.
/// @param account The address of the account to snapshot.
/// @return The account snapshot of `account`.
function getSnapshot(
address account
) external view returns (AccountSnapshot memory);
/// @notice Total number of cTokens in circulation.
function totalSupply() external view returns (uint256);
/// @notice Returns the total amount of assets held by the market.
/// @return The total amount of assets held by the market.
function totalAssets() external view returns (uint256);
/// @notice Address of the Market Manager linked to this contract.
function marketManager() external view returns (IMarketManager);
/// @notice Returns the amount of assets that would be exchanged
/// by the vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @return The number of assets a user would receive for converting
/// `shares`.
function convertToAssets(uint256 shares) external view returns (uint256);
/// @notice Updates pending assets and returns the up-to-date exchange
/// rate from the underlying to the BorrowableCToken.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
/// @return The share -> asset exchange rate, in `WAD`.
function exchangeRateUpdated() external returns (uint256) ;
/// @notice Returns the up-to-date exchange rate from the underlying to
/// the BorrowableCToken.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
/// @return The share -> asset exchange rate, in `WAD`.
function exchangeRate() external view returns (uint256);
/// @notice Executes multiple calls in a single transaction.
/// This can be used to update oracle prices before
/// a liquidity dependent action.
function multicall(
Multicall.MulticallAction[] memory calls
) external returns (bytes[] memory results);
/// @notice Caller deposits `assets` into the market and `receiver`
/// receives shares.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function deposit(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev The caller must be depositing for themselves, or be managing
/// their position through a Position Manager contract.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateral(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev Requires that `receiver` approves the caller prior to
/// collateralize on their behalf.
/// NOTE: Be careful who you approve here!
/// They can delay redemption of assets through repeated
/// collateralization preventing withdrawal.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateralFor(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to be redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner`.
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares, sending assets to `receiver`.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Caller withdraws assets from the market and burns their
/// shares, on behalf of `owner`.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemCollateralFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param owner The owner address of assets to redeem.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function withdrawByPositionManager(
uint256 assets,
address owner,
IPositionManager.DeleverageAction memory action
) external;
/// @notice Amount of tokens that has been posted as collateral,
/// in shares.
function marketCollateralPosted() external view returns (uint256);
/// @notice Shares of this token that an account has posted as collateral.
/// @param account The address of the account to check collateral posted
/// of.
function collateralPosted(address account) external view returns (uint256);
/// @notice Transfers tokens from `account` to `liquidator`.
/// @dev Will fail unless called by a cToken during the process
/// of liquidation.
/// @param shares An array containing the number of cToken shares
/// to seize.
/// @param liquidator The account receiving seized cTokens.
/// @param accounts An array containing the accounts having
/// collateral seized.
function seize(
uint256[] calldata shares,
address liquidator,
address[] calldata accounts
) external;
/// @notice Allows users to simulate the effects of their deposit at
/// the current block.
/// @param assets The number of assets to preview a deposit call.
/// @return The shares received for depositing `assets`.
function previewDeposit(uint256 assets) external view returns (uint256);
}
// contracts/interfaces/IExternalCalldataChecker.sol
interface IExternalCalldataChecker {
/// @notice Inspects calldata for compliance with other swap instruction
/// parameters.
/// @dev Used on swap to inspect and validate calldata safety.
/// @param swapAction Swap action instructions including both direct
/// parameters and decodeable calldata.
/// @param expectedRecipient Address who will receive proceeds of
/// `swapAction`.
function checkCalldata(
SwapperLib.Swap memory swapAction,
address expectedRecipient
) external;
}
// contracts/interfaces/IOracleManager.sol
interface IOracleManager {
/// @notice Retrieves the price of a specified asset from either single
/// or dual oracles.
/// @dev If the asset has one oracle, it fetches the price from a single feed.
/// If it has two or more oracles, it fetches the price from both feeds.
/// @param asset The address of the asset to retrieve the price for.
/// @param inUSD Whether the price should be returned in USD or ETH.
/// @param getLower Whether the lower or higher price should be returned
/// if two feeds are available.
/// @return price The current price of `asset`.
/// @return errorCode An error code related to fetching the price:
/// '0' indicates no error fetching price.
/// '1' indicates that price should be taken with
/// caution.
/// '2' indicates a complete failure in receiving
/// a price.
function getPrice(
address asset,
bool inUSD,
bool getLower
) external view returns (uint256 price, uint256 errorCode);
/// @notice Retrieves the prices of a collateral token and debt token
/// underlyings.
/// @param collateralToken The cToken currently collateralized to price.
/// @param debtToken The cToken borrowed from to price.
/// @param errorCodeBreakpoint The error code that will cause liquidity
/// operations to revert.
/// @return collateralUnderlyingPrice The current price of
/// `collateralToken` underlying.
/// @return debtUnderlyingPrice The current price of `debtToken`
/// underlying.
function getPriceIsolatedPair(
address collateralToken,
address debtToken,
uint256 errorCodeBreakpoint
) external returns (uint256, uint256);
/// @notice Retrieves the prices and account data of multiple assets
/// inside a Curvance Market.
/// @param account The account to retrieve data for.
/// @param assets An array of asset addresses to retrieve the prices for.
/// @param errorCodeBreakpoint The error code that will cause liquidity
/// operations to revert.
/// @return AccountSnapshot[] Contains `assets` data for `account`
/// @return uint256[] Contains prices for `assets`.
/// @return uint256 The number of assets `account` is in.
function getPricesForMarket(
address account,
address[] calldata assets,
uint256 errorCodeBreakpoint
)
external
returns (AccountSnapshot[] memory, uint256[] memory, uint256);
/// @notice Potentially removes the dependency on pricing from `adaptor`
/// for `asset`, triggered by an adaptor's notification of a price
/// feed's removal.
/// @notice Removes a pricing adaptor for `asset` triggered by an
/// adaptor's notification of a price feed's removal.
/// @dev Requires that the adaptor is currently being used for pricing
/// for `asset`.
/// NOTE: This intentionally does not modify asset deviation values
/// because they simply wont be used if there are less than two
/// pricing adaptors in use, so no reason to delete data as
/// when a second pricing adaptor is configured the deviation
/// has the opportunity be to reconfigured anyway.
/// @param asset The address of the asset to potentially remove the
/// pricing adaptor dependency from depending on current
/// `asset` configuration.
function notifyFeedRemoval(address asset) external;
/// @notice Returns the adaptors used for pricing `asset`.
/// @param asset The address of the asset to get pricing adaptors for.
/// @return The current adaptor(s) used for pricing `asset`.
function getPricingAdaptors(
address asset
) external view returns(address[] memory);
/// @notice Address => Adaptor approval status.
/// @param adaptor The address of the adaptor to check.
/// @return True if the adaptor is supported, false otherwise.
function isApprovedAdaptor(address adaptor) external view returns (bool);
/// @notice Whether a token is recognized as a Curvance token or not,
/// if it is, will return its underlying asset address instead
/// of address (0).
/// @return The cToken's underlying asset, or address(0) if not a cToken.
function cTokens(address cToken) external view returns (address);
/// @notice Checks if a given asset is supported by the Oracle Manager.
/// @dev An asset is considered supported if it has one
/// or more associated price feeds.
/// @param asset The address of the asset to check.
/// @return True if the asset is supported, false otherwise.
function isSupportedAsset(address asset) external view returns (bool);
/// @notice Check whether L2 sequencer is valid or down.
/// @return True if sequencer is valid.
function isSequencerValid() external view returns (bool);
}
// contracts/interfaces/IPositionManager.sol
interface IPositionManager {
/// TYPES ///
/// @notice Instructions for a leverage action.
/// @param borrowableCToken Address of the borrowableCToken that will be
/// borrowed from and assets swapped into `cToken`
/// asset.
/// @param borrowAssets The amount borrowed from `borrowableCToken`,
/// in assets.
/// @param cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// @param expectedShares The expected shares received from depositing
/// into `cToken` with swapped `borrowAssets`.
/// @param swapAction Swap action instructions converting debt asset into
/// collateral asset to facilitate leveraging.
/// @param auxData Optional auxiliary data for execution of a leverage
/// action.
struct LeverageAction {
IBorrowableCToken borrowableCToken;
uint256 borrowAssets;
ICToken cToken;
uint256 expectedShares;
SwapperLib.Swap swapAction;
bytes auxData;
}
/// @notice Instructions for a deleverage action.
/// @param cToken Address of the cToken that will be redeemed from and
/// assets swapped into `borrowableCToken` asset.
/// @param collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// @param borrowableCToken Address of the borrowableCToken that will
/// have its debt paid.
/// @param repayAssets The amount of `borrowableCToken` asset that will
/// be repaid to lenders.
/// @param swapActions Swap actions instructions converting collateral
/// asset into debt asset to facilitate deleveraging.
/// @param auxData Optional auxiliary data for execution of a deleverage
/// action.
struct DeleverageAction {
ICToken cToken;
uint256 collateralAssets;
IBorrowableCToken borrowableCToken;
uint256 repayAssets;
SwapperLib.Swap[] swapActions;
bytes auxData;
}
/// @notice Callback function to execute post borrow of
/// `borrowableCToken`'s asset and swap it to deposit
/// new collateralized shares for `owner`.
/// @dev Measures slippage after this callback validating that `owner`
/// is still within acceptable liquidity requirements.
/// @param borrowableCToken The borrowableCToken borrowed from.
/// @param borrowAssets The amount of `borrowableCToken`'s asset borrowed.
/// @param owner The account borrowing that will be swapped into
/// collateral assets deposited into Curvance.
/// @param action Instructions for a leverage action containing:
/// borrowableCToken Address of the borrowableCToken that
/// will be borrowed from and assets
/// swapped into `cToken` asset.
/// borrowAssets The amount borrowed from
/// `borrowableCToken`, in assets.
/// cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// swapAction Swap action instructions converting debt
/// asset into collateral asset to facilitate
/// leveraging.
/// auxData Optional auxiliary data for execution of a
/// leverage action.
function onBorrow(
address borrowableCToken,
uint256 borrowAssets,
address owner,
LeverageAction memory action
) external;
/// @notice Callback function to execute post redemption of `cToken`'s
/// asset and swap it to repay outstanding debt for `owner`.
/// @dev Measures slippage after this callback validating that `owner`
/// is still within acceptable liquidity requirements.
/// @param cToken The Curvance token redeemed for its underlying.
/// @param collateralAssets The amount of `cToken` underlying redeemed.
/// @param owner The account redeeming collateral that will be used to
/// repay their active debt.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapAction Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function onRedeem(
address cToken,
uint256 collateralAssets,
address owner,
DeleverageAction memory action
) external;
}
// contracts/libraries/SwapperLib.sol
/// @title Curvance Swapper Library.
/// @notice Helper Library for performing composable swaps with varying
/// degrees of slippage tolerance. "Unsafe" swaps perform a standard
/// slippage check whereas "safe" swaps not only check for standard
/// slippage but also check against the Oracle Manager's prices as
/// well.
/// NOTE: This library does not intend to provide support for fee on
/// transfer tokens though support may be built in the future.
library SwapperLib {
/// TYPES ///
/// @notice Instructions to execute a swap, selling `inputToken` for
/// `outputToken`.
/// @param inputToken Address of input token to swap from.
/// @param inputAmount The amount of `inputToken` to swap.
/// @param outputToken Address of token to swap into.
/// @param target Address of the swapper, usually an aggregator.
/// @param slippage The amount of value-loss acceptable from swapping
/// between tokens.
/// @param call Swap instruction calldata.
struct Swap {
address inputToken;
uint256 inputAmount;
address outputToken;
address target;
uint256 slippage;
bytes call;
}
/// @notice Address identifying a chain's native token.
address public constant native =
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// ERRORS ///
error SwapperLib__UnknownCalldata();
error SwapperLib__TokenPrice(address inputToken);
error SwapperLib__Slippage(uint256 slippage);
error SwapperLib__SameTokens();
/// INTERNAL FUNCTIONS ///
/// @notice Swaps `action.inputToken` into a `action.outputToken`
/// without an extra slippage check.
/// @param cr The address of the Protocol Central Registry to pull
/// addresses from.
/// @param action Instructions for a swap action containing:
/// inputToken Address of input token to swap from.
/// inputAmount The amount of `inputToken` to swap.
/// outputToken Address of token to swap into.
/// target Address of the swapper, usually an aggregator.
/// slippage The amount of value-loss acceptable from
/// swapping between tokens.
/// call Swap instruction calldata.
/// @return outAmount The output amount received from swapping.
function _swapUnsafe(
ICentralRegistry cr,
Swap memory action
) internal returns (uint256 outAmount) {
address outputToken = action.outputToken;
address inputToken = action.inputToken;
// Do not use this library if the tokens are the same.
if (CommonLib._isMatchingToken(inputToken, outputToken)) {
revert SwapperLib__SameTokens();
}
address callDataChecker = cr.externalCalldataChecker(action.target);
// Validate we know how to verify this calldata.
if (callDataChecker == address(0)) {
revert SwapperLib__UnknownCalldata();
}
// Verify calldata integrity.
IExternalCalldataChecker(callDataChecker)
.checkCalldata(action, address(this));
// Approve `action.inputToken` to target contract, if necessary.
_approveIfNeeded(inputToken, action.target, action.inputAmount);
// Cache output token from struct for easier querying.
uint256 balanceBefore = CommonLib._balanceOf(outputToken);
uint256 callValue = CommonLib._isNative(inputToken) ?
action.inputAmount : 0;
// Execute the swap.
LowLevelCallsHelper._callWithNative(
action.target,
action.call,
callValue
);
// Remove any excess approval.
_removeApprovalIfNeeded(inputToken, action.target);
outAmount = CommonLib._balanceOf(outputToken) - balanceBefore;
}
/// @notice Swaps `action.inputToken` into a `action.outputToken`
/// with an extra slippage check.
/// @param cr The address of the Protocol Central Registry to pull
/// addresses from.
/// @param action Instructions for a swap action containing:
/// inputToken Address of input token to swap from.
/// inputAmount The amount of `inputToken` to swap.
/// outputToken Address of token to swap into.
/// target Address of the swapper, usually an
/// aggregator.
/// slippage The amount of value-loss acceptable from
/// swapping between tokens.
/// call Swap instruction calldata.
/// @return outAmount The output amount received from swapping.
function _swapSafe(
ICentralRegistry cr,
Swap memory action
) internal returns (uint256 outAmount) {
if (action.slippage >= WAD) {
revert SwapperLib__Slippage(action.slippage);
}
outAmount = _swapUnsafe(cr, action);
IOracleManager om = CommonLib._oracleManager(cr);
uint256 valueIn = _getValue(om, action.inputToken, action.inputAmount);
uint256 valueOut = _getValue(om, action.outputToken, outAmount);
// Check if swap received positive slippage.
if (valueOut > valueIn) {
return outAmount;
}
// Calculate % slippage from executed swap.
uint256 slippage = FixedPointMathLib.mulDivUp(
valueIn - valueOut,
WAD,
valueIn
);
if (slippage > action.slippage) {
revert SwapperLib__Slippage(slippage);
}
}
/// @notice Get the value of a token amount.
/// @notice Approves `token` spending allowance, if needed.
/// @param om The Oracle Manager address to call for pricing `token`.
/// @param token The token address to get the value of.
/// @param amount The amount of `token` to get the value of.
function _getValue(
IOracleManager om,
address token,
uint256 amount
) internal view returns (uint256 result) {
// If token is native, normalize to address(0) so it is compatible
// with the Oracle Manager.
if (token == address(0)) {
token = native;
}
(uint256 price, uint256 errorCode) = om.getPrice(token, true, true);
if (errorCode != NO_ERROR) {
revert SwapperLib__TokenPrice(token);
}
// Return price in WAD form.
result = FixedPointMathLib.mulDiv(
price,
amount,
10 ** (CommonLib._isNative(token) ? 18 : IERC20(token).decimals())
);
}
/// @notice Approves `token` spending allowance, if needed.
/// @param token The token address to approve.
/// @param spender The spender address.
/// @param amount The approval amount.
function _approveIfNeeded(
address token,
address spender,
uint256 amount
) internal {
if (!CommonLib._isNative(token)) {
SafeTransferLib.safeApprove(token, spender, amount);
}
}
/// @notice Removes `token` spending allowance, if needed.
/// @param token The token address to remove approval.
/// @param spender The spender address.
function _removeApprovalIfNeeded(address token, address spender) internal {
if (!CommonLib._isNative(token)) {
if (IERC20(token).allowance(address(this), spender) > 0) {
SafeTransferLib.safeApprove(token, spender, 0);
}
}
}
}
// contracts/market/token/BaseCToken.sol
/// @notice Curvance's cTokens (Curvance Tokens) follow their own design modifying underlying
/// mechanisms such as `totalAssets` following an asset vesting system
/// in both external strategies and lender interest accrual from
/// borrowers.
///
/// "Weird tokens" that do not properly implement ERC-20 are not
/// intended to be supported such as where name() or decimals()
/// returns in unconventional forms.
///
/// The "cToken" employs two different methods of engaging with the
/// Curvance protocol. Users can deposit an unlimited amount of assets,
/// which may or may not benefit from some form of yield.
///
/// Users can at any time, choose to "post" their cTokens as collateral
/// inside the Curvance Protocol, unlocking their ability to borrow
/// against these assets. Posting collateral carries restrictions,
/// not all assets inside Curvance can be collateralized, and if they
/// can, they have a "Collateral Cap" which restricts the total amount of
/// exogeneous risk introduced by each asset into the system.
///
/// These caps can be updated as needed by the DAO and should be
/// configured based on "sticky" onchain liquidity in the corresponding
/// asset.
///
/// Each token can have their minting, collateralization, borrowing,
/// compounding, liquidations, and redemption functionality paused.
/// Modifying the maximum mint, deposit, withdrawal, or redemptions
/// possible.
///
/// View functions are "safe" by introducing reentry and update
/// protection to minimize risks when integrating with Curvance.
///
/// @dev Curvance cTokens are partially ERC-4626 compliant:
/// - Zero-amount transfers are blocked.
/// - `convertToShares()` and `convertToAssets()` use `nonReadReentrant`, which may revert
/// under reentrancy, deviating from ERC-4626 view requirements.
/// - `maxWithdraw()` and `maxRedeem()` do not reflect global withdrawal limits.
/// These deviations are intentional to prioritize protocol-level risk controls,
/// reentrancy protection, and flexibility. Integrators should not rely on strict
/// ERC-4626 behavior.
///
/// `Asset()` Positions must have all assets ready for withdraw,
/// IE assets can NOT be locked.
/// This way assets can be easily liquidated when loans default.
abstract contract BaseCToken is
ERC4626,
PluginDelegable,
ReentrancyGuard,
Multicall,
ERC165
{
/// CONSTANTS ///
/// @dev `bytes4(keccak256(bytes("BaseCToken__Unauthorized()")))`
uint256 internal constant _UNAUTHORIZED_SELECTOR = 0x471656c5;
/// @dev `bytes4(keccak256(bytes("BaseCToken__InsufficientLiquidity()")))`
uint256 internal constant _INSUFFICIENT_LIQUIDITY_SELECTOR = 0xe6c95926;
/// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
uint256 internal constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/// @dev The balance slot of `owner` is given by:
/// ```
/// mstore(0x0c, _BALANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let balanceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 internal constant _BALANCE_SLOT_SEED = 0x87a211a2;
/// @dev The base underlying asset requirement held in order to minimize
/// rounding exploits, and more generally, invariant manipulation.
uint256 internal constant _BASE_UNDERLYING_RESERVE = 77777;
/// @notice Address of the Market Manager linked to this contract.
IMarketManager public immutable marketManager;
/// @notice Underlying asset for this token.
/// @dev CANNOT be a fee-on-transfer token.
IERC20 internal immutable _asset;
/// @notice Token decimal precision.
uint8 internal immutable _decimals;
/// STORAGE ///
/// @notice Amount of tokens that has been posted as collateral,
/// in shares.
uint256 public marketCollateralPosted;
/// @notice Token name metadata.
string internal _name;
/// @notice Token symbol metadata.
string internal _symbol;
/// @notice Total amount of `asset()` in this vault, minus pending
/// vesting.
uint256 internal _totalAssets;
/// @notice Shares of this token that an account has posted as collateral.
/// @dev Account address => Collateral data.
mapping(address => uint256) public collateralPosted;
/// EVENTS ///
event CollateralUpdated(uint256 shares, bool increased, address account);
event Liquidated(uint256 shares, address liquidator, address account);
/// ERRORS ///
error BaseCToken__ZeroAmount();
error BaseCToken__TransferError();
error BaseCToken__InsufficientLiquidity();
error BaseCToken__Unauthorized();
error BaseCToken__UnsupportedChain();
error BaseCToken__InvalidMarketManager();
error BaseCToken__InvariantError();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
/// @param asset_ The address of the underlying asset for this cToken.
/// @param mm The address of the MarketManager which manages liquidity
/// positions between linked cTokens inside a joint market.
constructor(
ICentralRegistry cr,
IERC20 asset_,
address mm
) PluginDelegable(cr) {
_asset = asset_;
_name = string.concat("Curvance ", asset_.name());
_symbol = string.concat("c", asset_.symbol());
_decimals = asset_.decimals();
// Validate that `mm` is configured as a Market Manager inside the
// Protocol Central Registry.
if (!centralRegistry.isMarketManager(mm)) {
revert BaseCToken__InvalidMarketManager();
}
// Set `marketManager`.
marketManager = IMarketManager(mm);
}
/// EXTERNAL FUNCTIONS ///
/// @notice Enables a token's functionality inside a market, executed
/// via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// NOTE: ONLY CALLED ONCE DURING TOKEN LISTING BY DAO AUTHORIZED
/// ADDRESS FROM THE MARKET MANAGER.
/// @param by The account initializing deposits.
/// @return Returns with true when successful.
function initializeDeposits(
address by
) external nonReentrant returns (bool) {
_initializeDeposits(by);
return true;
}
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param owner The owner address of assets to redeem.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function withdrawByPositionManager(
uint256 assets,
address owner,
IPositionManager.DeleverageAction memory action
) external nonReentrant {
// Validate that a position manager is calling.
if (!marketManager.isPositionManager(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
_accrueIfNeeded();
// Use up-to-date total assets including any pending vesting via getter.
uint256 ta = _getTotalAssets();
uint256 balance = _checkRedemption(assets, owner, ta);
// No need to check for rounding error, previewWithdraw rounds up.
uint256 shares = _previewWithdraw(assets, ta);
_processWithdraw(assets, shares, msg.sender, msg.sender, owner);
// Process the position manager redemption leg.
_processPositionManagerRedemption(
assets,
shares,
owner,
balance,
action
);
}
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev The caller must be collateralizing for themselves, or be managing
/// their position through a Position Manager contract.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function depositAsCollateral(
uint256 assets,
address receiver
) external nonReentrant returns (uint256 shares) {
if (
msg.sender != receiver &&
!marketManager.isPositionManager(msg.sender)
) {
_revert(_UNAUTHORIZED_SELECTOR);
}
shares = _deposit(assets, receiver);
// Can skip _checkPostCollateral since we know that `shares` is not
// 0 and `receiver` has shares to post as collateral due to prior
// _deposit action.
_postCollateral(shares, receiver);
}
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev Requires that `receiver` approves the caller prior to
/// collateralize on their behalf.
/// NOTE: Be careful who you approve here!
/// They can delay redemption of assets through repeated
/// collateralization preventing withdrawal.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function depositAsCollateralFor(
uint256 assets,
address receiver
) external nonReentrant returns (uint256 shares) {
_checkDelegate(receiver, msg.sender);
shares = _deposit(assets, receiver);
// Can skip _checkPostCollateral since we know that `shares` is not
// 0 and `receiver` has shares to post as collateral due to prior
// _deposit action.
_postCollateral(shares, receiver);
}
/// @notice Caller withdraws assets from the market and burns their shares.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param assets The amount of the underlying assets to withdraw.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw assets.
/// @return shares the amount of cToken shares redeemed by `owner`.
function withdrawCollateral(
uint256 assets,
address receiver,
address owner
) external nonReentrant returns (uint256 shares) {
shares = _withdraw(assets, receiver, owner, true);
}
/// @notice Caller withdraws assets from the market and burns their shares.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw assets.
/// @return assets the amount of assets redeemed by `owner`.
function redeemCollateral(
uint256 shares,
address receiver,
address owner
) external nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, false, true);
}
/// @notice Caller withdraws assets from the market and burns their
/// shares, on behalf of `owner`.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemCollateralFor(
uint256 shares,
address receiver,
address owner
) external nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, true, true);
}
/// @notice Posts `shares` as collateral inside this market.
/// @dev The cToken must have collateralization enabled (collRatio > 0),
/// and its collateral cap set (above 0).
/// @param shares The amount of shares to post as collateral.
function postCollateral(uint256 shares) external nonReentrant {
_checkPostCollateral(shares, msg.sender);
_postCollateral(shares, msg.sender);
}
/// @notice Posts `shares` as collateral inside this market
/// for `account`.
/// @dev The cToken must have collateralization enabled (collRatio > 0),
/// and its collateral cap set (above 0).
/// @param shares The number of shares to post as collateral from `owner`.
/// @param owner The address of the account posting `shares`
/// as collateral.
function postCollateralFor(
uint256 shares,
address owner
) external nonReentrant {
_checkDelegate(owner, msg.sender);
_checkPostCollateral(shares, owner);
_postCollateral(shares, owner);
}
/// @notice Removes `shares` of collateral posted inside this market.
/// @param shares The number of shares that are posted of collateral
/// that will be removed.
function removeCollateral(uint256 shares) external nonReentrant {
_checkRemoveCollateral(shares, msg.sender);
_removeCollateral(shares, msg.sender);
}
/// @notice Removes `shares` of collateral posted inside this market
/// for `account`.
/// @param shares The number of shares to remove as collateral
/// from `owner`.
/// @param owner The address of the account removing `shares`
/// as collateral.
function removeCollateralFor(
uint256 shares,
address owner
) external nonReentrant {
_checkDelegate(owner, msg.sender);
_checkRemoveCollateral(shares, owner);
_removeCollateral(shares, owner);
}
/// @notice Transfers collateralized cToken shares from `accounts`
/// to `liquidator` as part of a liquidation.
/// @dev Will fail unless called by a different listed cToken
/// during the process of liquidation.
/// May emit {CollateralUpdated} and {Liquidated} events.
/// @param liquidatedShares An array containing the number of
/// collateralized cTokens to seize, in shares.
/// @param liquidator The account receiving `liquidatedShares` cTokens.
/// @param accounts An array containing the accounts having collateral
/// seized.
function seize(
uint256[] calldata liquidatedShares,
address liquidator,
address[] calldata accounts
) external nonReentrant {
// Fails if seizure not allowed.
marketManager.canSeize(address(this), msg.sender);
// We know that `accounts` and `liquidatedShares` arrays are the same
// length since we validate it inside the cToken getting debt repaid
// as part of this liquidation.
uint256 numAccounts = accounts.length;
uint256 totalShares;
uint256 shares;
address account;
for (uint256 i; i < numAccounts; ++i) {
shares = liquidatedShares[i];
// If theres no shares to liquidate for this account can
// skip them.
if (shares == 0) {
continue;
}
account = accounts[i];
// Execute any prior liquidation action.
_beforeLiqAction(shares, liquidator, account);
totalShares += shares;
// Update `account` collateral posted invariant and transfer
// their collateral shares.
collateralPosted[account] = collateralPosted[account] - shares;
emit CollateralUpdated(shares, false, account);
// Transfer liquidated shares from `account` to `liquidator`.
_transferFromWithoutAllowance(account, liquidator, shares);
emit Liquidated(shares, liquidator, account);
}
// Update market collateral posted invariant for the liquidated
// shares.
marketCollateralPosted = marketCollateralPosted - totalShares;
}
/// @notice Updates pending assets and returns the up-to-date exchange
/// rate from the underlying to the BorrowableCToken.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
/// @return result The share -> asset exchange rate, in `WAD`.
function exchangeRateUpdated() external returns (uint256 result) {
_accrueIfNeeded();
result = _convertToAssets(WAD, _getTotalAssets());
}
/// @notice Returns the up-to-date exchange rate from the underlying to
/// the BorrowableCToken.
/// @return result The share -> asset exchange rate, in `WAD`.
function exchangeRate() external view returns (uint256 result) {
result = _convertToAssets(WAD, _getTotalAssets());
}
/// @notice Updates pending assets and returns a snapshot of the cToken
/// and `account` data.
/// @dev Used by MarketManager to efficiently perform liquidity checks.
/// NOTE: debtBalance always return 0 except in `borrowableCToken`.
/// @return result The snapshot of the cToken and `account` data.
function getSnapshotUpdated(
address account
) external returns (AccountSnapshot memory result) {
_accrueIfNeeded();
result = getSnapshot(account);
}
/// PUBLIC FUNCTIONS ///
/// @notice Returns a snapshot of the cToken and `account` data.
/// @dev debtBalance always return 0 except in `borrowableCToken`.
/// NOTE: Does not accrue pending assets as part of the call.
/// @return result The snapshot of the cToken and `account` data.
function getSnapshot(
address account
) public view virtual returns (AccountSnapshot memory result) {
result.asset = address(this);
result.underlying = address(_asset);
result.decimals = decimals();
// Can only be true for non-BorrowableCTokens.
result.isCollateral = true;
result.collateralPosted = collateralPosted[account];
// result.debtBalance is 0 for non-BorrowableCTokens, no need to set.
}
/// @notice Returns the name of the token.
/// @return The name of the token.
function name() public view override returns (string memory) {
return _name;
}
/// @notice Returns the symbol of the token.
/// @return The symbol of the token.
function symbol() public view override returns (string memory) {
return _symbol;
}
/// @notice Returns the address of the underlying asset.
/// @return result The address of the underlying asset.
function asset() public view override returns (address result) {
result = address(_asset);
}
/// @notice Returns the maximum assets that can be deposited at a time.
/// @dev If depositing is disabled maxAssets should be equal to 0,
/// according to ERC4626 spec.
/// @param receiver The address who would receive minted shares.
/// @return maxAssets The maximum assets that can be deposited at a time.
function maxDeposit(
address receiver
) public view override returns (uint256 maxAssets) {
(bool mintPaused, , ) = marketManager.actionsPaused(address(this));
if (!marketManager.isListed(address(this)) || mintPaused) {
// We do not need to set maxAssets here since its initialized
// as 0 so we can just return.
return maxAssets;
}
maxAssets = super.maxDeposit(receiver);
}
/// @notice Returns the maximum shares that can be minted at a time.
/// @dev If depositing is disabled minMint should be equal to 0,
/// according to ERC4626 spec.
/// @param receiver The address who would receive minted shares.
/// @return maxShares The maximum shares that can be minted at a time.
function maxMint(
address receiver
) public view override returns (uint256 maxShares) {
(bool mintPaused, , ) = marketManager.actionsPaused(address(this));
if (!marketManager.isListed(address(this)) || mintPaused) {
// We do not need to set maxShares here since its initialized
// as 0 so we can just return.
return maxShares;
}
maxShares = super.maxMint(receiver);
}
/// @notice Caller deposits `assets` into the market and `receiver`
/// receives shares.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function deposit(
uint256 assets,
address receiver
) public override nonReentrant returns (uint256 shares) {
shares = _deposit(assets, receiver);
}
/// @notice Caller deposits `shares` into the market and `receiver`
/// receives shares.
/// @param shares The amount of the underlying assets quoted in shares
/// to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return assets The amount of cToken shares quoted in assets received
/// by `receiver`.
function mint(
uint256 shares,
address receiver
) public override nonReentrant returns (uint256 assets) {
assets = _mint(shares, receiver);
}
/// @notice Withdraws `assets` from the market, and burns `owner` shares.
/// @dev Does not force collateral posted to be withdrawn.
/// @param assets The amount of the underlying assets to withdraw.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return shares The amount of cToken shares redeemed by `owner`.
function withdraw(
uint256 assets,
address receiver,
address owner
) public override nonReentrant returns (uint256 shares) {
shares = _withdraw(assets, receiver, owner, false);
}
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to be redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner`.
function redeem(
uint256 shares,
address receiver,
address owner
) public override nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, false, false);
}
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares, sending assets to `receiver`.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemFor(
uint256 shares,
address receiver,
address owner
) public nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, true, false);
}
/// @notice Transfers `amount` tokens from caller to `to`.
/// @param receiver The address of the destination account to receive
/// `shares` shares.
/// @param shares The number of shares to transfer from caller to
/// `receiver`.
/// @return Whether or not the transfer succeeded or not.
function transfer(
address receiver,
uint256 shares
) public override nonReentrant returns (bool) {
_checkTransfer(shares, receiver, msg.sender);
// Execute transfer.
super.transfer(receiver, shares);
return true;
}
/// @notice Transfers `amount` tokens from `owner` to `receiver`.
/// @param owner The address of the account transferring `shares`
/// shares from.
/// @param receiver The address of the destination account to receive
/// `shares` shares.
/// @param shares The number of shares to transfer from `owner` to
/// `receiver`.
/// @return Whether or not the transfer succeeded or not.
function transferFrom(
address owner,
address receiver,
uint256 shares
) public override nonReentrant returns (bool) {
_checkTransfer(shares, receiver, owner);
// Execute transfer.
super.transferFrom(owner, receiver, shares);
return true;
}
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return result Whether this token is borrowable or not.
function isBorrowable() public pure virtual returns (bool result) {
result = false;
}
/// @dev Returns true that this contract implements both ERC4626
/// and ICToken interfaces.
/// @param interfaceId The interface ID to check.
/// @return result Whether the contract implements the interface.
function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool result) {
result = interfaceId == type(ICToken).interfaceId ||
interfaceId == type(ERC4626).interfaceId ||
super.supportsInterface(interfaceId);
}
/// @notice Returns the total number of assets backing shares.
/// @return result The total number of assets backing shares.
function totalAssets() public view nonReadReentrant override returns (
uint256 result
) {
result = _getTotalAssets();
}
/// @notice Returns the amount of shares that would be exchanged
/// by the vault for `assets` provided.
/// @param assets The number of assets to theoretically use
/// for conversion to shares.
/// @return The number of shares a user would receive for converting
/// `assets`.
function convertToShares(
uint256 assets
) public view nonReadReentrant override returns (uint256) {
return _convertToShares(assets, _getTotalAssets());
}
/// @notice Returns the amount of assets that would be exchanged
/// by the vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @return The number of assets a user would receive for converting
/// `shares`.
function convertToAssets(
uint256 shares
) public view nonReadReentrant override returns (uint256) {
return _convertToAssets(shares, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their deposit at
/// the current block.
/// @param assets The number of assets to preview a deposit call.
/// @return The shares received for depositing `assets`.
function previewDeposit(
uint256 assets
) public view override returns (uint256) {
return _convertToShares(assets, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their mint at
/// the current block.
/// @param shares The number of assets, quoted as shares to preview
/// a mint call.
/// @return The shares received quoted as assets for depositing `shares`.
function previewMint(
uint256 shares
) public view override returns (uint256) {
return _previewMint(shares, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their withdraw
/// at the current block.
/// @param assets The number of assets to preview a withdraw call.
/// @return The assets received quoted as shares for withdrawing `assets`.
function previewWithdraw(
uint256 assets
) public view virtual override returns (uint256) {
return _previewWithdraw(assets, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their redeem at
/// the current block.
/// @param shares The number of assets, quoted as shares to preview
/// a redeem call.
/// @return The assets received for withdrawing `shares`.
function previewRedeem(
uint256 shares
) public view virtual override returns (uint256) {
return _convertToAssets(shares, _getTotalAssets());
}
/// @notice Can accrue pending yield, configure next vesting
/// period, and updates vesting data, if needed.
/// @dev May emit a {RatesAdjusted} event.
function accrueIfNeeded() external nonReentrant {
_accrueIfNeeded();
}
/// INTERNAL FUNCTIONS ///
/// @notice Deposits `assets` and mints shares to `receiver`.
/// @param assets The amount of the underlying asset to supply.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function _deposit(
uint256 assets,
address receiver
) internal virtual returns (uint256 shares) {
_accrueIfNeeded();
// Check for rounding error by converting assets to shares,
// since we round down in previewDeposit.
_checkZeroAmount(shares = _convertToShares(assets, _getTotalAssets()));
// Fails if deposit not allowed, this stands in for a maxDeposit
// check reviewing isListed and mintPaused != 2.
marketManager.canMint(address(this));
// Execute deposit.
_processDeposit(assets, shares, msg.sender, receiver);
}
/// @notice Deposits assets and mints `shares` to `receiver`.
/// @param shares The amount of the underlying assets quoted in shares
/// to supply.
/// @param receiver The account that should receive the cToken shares.
/// @return assets The amount of cToken shares quoted in assets received
/// by `receiver`.
function _mint(
uint256 shares,
address receiver
) internal virtual returns (uint256 assets) {
_accrueIfNeeded();
_checkZeroAmount(shares);
// Fail if mint not allowed, this stands in for a maxMint
// check reviewing isListed and mintPaused != 2.
marketManager.canMint(address(this));
// Execute deposit.
// No need to check for rounding error, previewMint rounds up.
_processDeposit(
assets = _previewMint(shares, _getTotalAssets()),
shares,
msg.sender,
receiver
);
}
/// @notice Withdraws `assets` to `receiver` from the market and burns
/// `owner` shares.
/// @dev Withdraw calls do not support the delegation system intentionally
/// to minimize code attack surface.
/// @param assets The amount of the underlying asset to withdraw.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @param forceRedeemCollateral Whether the collateral should be always
/// reduced from `owner`'s collateralPosted.
/// @return shares The amount of assets, quoted in shares received
/// by `receiver`.
function _withdraw(
uint256 assets,
address receiver,
address owner,
bool forceRedeemCollateral
) internal virtual returns (uint256 shares) {
_accrueIfNeeded();
// Use up-to-date total assets including any pending vesting via getter.
uint256 ta = _getTotalAssets();
uint256 balance = _checkRedemption(assets, owner, ta);
// Validate caller is allowed to withdraw `shares` on behalf of
// `owner`.
_updateAllowance(owner, shares = _previewWithdraw(assets, ta));
// Validate that `owner` can redeem `shares`.
uint256 collateralRedeemed = marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balance,
collateralPosted[owner],
forceRedeemCollateral
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
// Execute withdrawal.
_processWithdraw(
assets,
shares,
msg.sender,
receiver,
owner
);
}
/// @notice Redeems assets to `receiver` from the market and burns
/// `owner` `shares`.
/// @dev Redemption calls support the delegation system, allowing
/// an alternative approval system in parallel with the native
/// erc20 system.
/// @param shares The amount of shares to burn to withdraw assets.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @param delegatedAction Whether the action is delegated and should
/// use delegation system instead of normal
/// approval system.
/// @param forceRedeemCollateral Whether the collateral should be always
/// reduced from `owner`'s collateralPosted.
/// @return assets The amount of assets received by `receiver`.
function _redeem(
uint256 shares,
address receiver,
address owner,
bool delegatedAction,
bool forceRedeemCollateral
) internal virtual returns (uint256 assets) {
_accrueIfNeeded();
// Use up-to-date total assets including any pending vesting via getter.
uint256 ta = _getTotalAssets();
uint256 balance = _checkRedemption(
assets = _convertToAssets(shares, ta),
owner,
ta
);
// Validate caller is allowed to withdraw `shares` on behalf of
// `owner`. Or whether the caller has delegated approval
// via plugin system or not.
if (delegatedAction) {
_checkDelegate(owner, msg.sender);
} else {
_updateAllowance(owner, shares);
}
// Validate that `owner` can redeem `shares`.
uint256 collateralRedeemed = marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balance,
collateralPosted[owner],
forceRedeemCollateral
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
// Execute withdrawal.
_processWithdraw(assets, shares, msg.sender, receiver, owner);
}
/// @notice Helper function for posting `shares` as collateral
/// for `account` inside this market.
/// @dev Emits {CollateralUpdated} event.
/// May emit {PositionUpdated} event inside Market Manager.
/// @param owner The account posting collateral.
/// @param shares The amount of shares to post as collateral.
function _postCollateral(
uint256 shares,
address owner
) internal virtual {
uint256 newNetCollateral = marketCollateralPosted + shares;
marketManager.canCollateralize(address(this), owner, newNetCollateral);
// Update user and market collateral posted invariants.
collateralPosted[owner] = collateralPosted[owner] + shares;
marketCollateralPosted = newNetCollateral;
emit CollateralUpdated(shares, true, owner);
}
/// @notice Helper function for removing `shares` collateral posted for
/// `account` inside this market.
/// @dev Emits a {CollateralUpdated} event.
/// May emit {PositionUpdated} event inside Market Manager.
/// @param shares The number of shares that are posted of collateral
/// that should be removed.
/// @param owner The address of the account to reduce collateral
/// posted from.
function _removeCollateral(uint256 shares, address owner) internal {
// Update user and market collateral posted invariants.
collateralPosted[owner] = collateralPosted[owner] - shares;
marketCollateralPosted = marketCollateralPosted - shares;
emit CollateralUpdated(shares, false, owner);
}
/// @notice Can accrue yield, configure next vesting
/// period, and updates vesting data, if needed.
function _accrueIfNeeded() internal virtual {}
/// @notice Processes a deposit of `assets` from the market and mints
/// shares to `owner`, then increases `ta` by `assets`,
/// and vests rewards if `pending` > 0.
/// @dev Emits a {Deposit} event.
/// @param assets The amount of the underlying asset to deposit.
/// @param shares The amount of shares minted to `to`.
/// @param by The account that is executing the deposit.
/// @param receiver The account that should receive `shares`.
function _processDeposit(
uint256 assets,
uint256 shares,
address by,
address receiver
) internal {
// Transfer the underlying assets to the contract.
SafeTransferLib.safeTransferFrom(asset(), by, address(this), assets);
// Vests any rewards,if there are any, then update `_totalAssets`
// invariant and prepare assets for withdrawal.
_updateAssetsForDeposit(assets);
// Mint `shares` to `receiver`.
// NOTE: This is the erc20 mint function, meaning this is effectively
// super._mint().
_mint(receiver, shares);
emit Deposit(by, receiver, assets, shares);
_afterDepositAction(shares, receiver);
}
/// @notice Processes a withdrawal of `shares` from the market by burning
/// `owner` shares and transferring `assets` to `receiver`, then
/// decreases `ta` by `assets`, and vests rewards if
/// `pending` > 0.
/// @dev Emits a {Withdraw} event.
/// @param assets The amount of the underlying asset to withdraw.
/// @param shares The amount of shares redeemed from `owner`.
/// @param by The account that is executing the withdrawal.
/// @param receiver The account that should receive `assets`.
/// @param owner The account that will have `shares` burned to withdraw
/// `assets`.
function _processWithdraw(
uint256 assets,
uint256 shares,
address by,
address receiver,
address owner
) internal virtual {
_beforeWithdrawAction(shares, owner);
// Burn `owner` `shares`.
_burn(owner, shares);
// Vests any rewards, if there are any, then update `_totalAssets`.
// invariant and prepare assets for withdrawal.
_updateAssetsForWithdrawal(assets);
// Transfer the underlying assets to `receiver`.
SafeTransferLib.safeTransfer(asset(), receiver, assets);
emit Withdraw(by, receiver, owner, assets, shares);
}
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param shares The amount of the shares to redeem.
/// @param owner The owner address of assets to redeem.
/// @param balancePrior The balance of shares `owner` has before this
/// redemption.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function _processPositionManagerRedemption(
uint256 assets,
uint256 shares,
address owner,
uint256 balancePrior,
IPositionManager.DeleverageAction memory action
) internal virtual {
// Callback to Position Manager to execute remaining deleverage logic.
IPositionManager(msg.sender).onRedeem(
address(this),
assets,
owner,
action
);
if (balancePrior != balanceOf(owner) + shares) {
revert BaseCToken__InvariantError();
}
// Fails if redemption not allowed.
uint256 collateralRedeemed = marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balancePrior,
collateralPosted[owner],
false
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
}
/// @notice Helper function to efficiently transfers cToken balances
/// without checking approvals.
/// @dev This is only used in liquidations where maximal gas
/// optimization improves protocol MEV competitiveness,
/// improving protocol safety.
/// Emits a {Transfer} event.
/// @param from The address of the account transferring `amount`
/// shares from.
/// @param to The address of the destination account to receive `amount`
/// shares.
/// @param amount The number of tokens to transfer from `from` to `to`.
function _transferFromWithoutAllowance(
address from,
address to,
uint256 amount
) internal {
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(
0x20,
0x20,
_TRANSFER_EVENT_SIGNATURE,
shr(96, from_),
shr(96, mload(0x0c))
)
}
}
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @dev Emits a {Deposit} event.
/// @param by The account initializing deposits.
function _initializeDeposits(address by) internal virtual {
if (msg.sender != address(marketManager)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
address cTokenAddress = address(this);
uint256 assets = _BASE_UNDERLYING_RESERVE;
SafeTransferLib.safeTransferFrom(asset(), by, cTokenAddress, assets);
// Because nobody can deposit into the market before initializeDeposits()
// is called, this will always be the initial call.
uint256 shares = _initialConvertToShares(assets);
_mint(address(0), shares);
_totalAssets = assets;
emit Deposit(by, address(0), assets, shares);
_afterDepositAction(shares, address(0));
}
/// @notice Updates the allowance for the caller.
/// @param owner The owner of the allowance.
/// @param amount The spent amount of the allowance.
function _updateAllowance(address owner, uint256 amount) internal {
if (msg.sender != owner) {
_spendAllowance(owner, msg.sender, amount);
}
}
/// @dev Returns the decimals of the underlying asset.
function _underlyingDecimals() internal view override returns (uint8) {
return _decimals;
}
/// @dev Override to disable virtual shares since _decimalsOffset is 0.
function _useVirtualShares() internal pure override returns (bool) {
return false;
}
/// @notice Returns the total amount of the underlying asset in the vault,
/// including pending rewards that are vested.
/// @return result The total number of underlying assets.
function _getTotalAssets() internal view virtual returns (uint256 result) {
result = _totalAssets;
}
/// @notice Returns the amount of shares that would be exchanged by the
/// vault for `assets` provided.
/// @param assets The number of assets to theoretically use
/// for conversion to shares.
/// @param ta The total number of assets to theoretically use
/// for conversion to shares.
/// @return shares The number of shares a user would receive for
/// converting `assets`.
function _convertToShares(
uint256 assets,
uint256 ta
) internal view returns (uint256 shares) {
uint256 totalShares = totalSupply();
shares = totalShares == 0
? assets
: FixedPointMathLib.fullMulDiv(assets, totalShares, ta);
}
/// @notice Returns the amount of assets that would be exchanged by the
/// vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @param ta The total number of assets to theoretically use
/// for conversion to assets.
/// @return assets The number of assets a user would receive for
/// converting `shares`.
function _convertToAssets(
uint256 shares,
uint256 ta
) internal view returns (uint256 assets) {
uint256 totalShares = totalSupply();
assets = totalShares == 0
? shares
: FixedPointMathLib.fullMulDiv(shares, ta, totalShares);
}
/// @notice Simulates the effects of a user mint at the current
/// block.
/// @param shares The number of shares to preview a mint call.
/// @param ta The total number of assets to simulate a mint at the
/// current block.
/// @return assets The assets received for minting `shares`.
function _previewMint(
uint256 shares,
uint256 ta
) internal view returns (uint256 assets) {
uint256 totalShares = totalSupply();
assets = totalShares == 0
? shares
: FixedPointMathLib.fullMulDivUp(shares, ta, totalShares);
}
/// @notice Simulates the effects of a user withdrawal at the current
/// block.
/// @param assets The number of assets to preview a withdrawal call.
/// @param ta The total number of assets to simulate a withdrawal at the
/// current block.
/// @return shares The shares received for withdrawing `assets`.
function _previewWithdraw(
uint256 assets,
uint256 ta
) internal view returns (uint256 shares) {
uint256 totalShares = totalSupply();
shares = totalShares == 0
? assets
: FixedPointMathLib.fullMulDivUp(assets, totalShares, ta);
}
/// @notice Updates asset values for a pending deposit.
/// @param assets The amount of `asset()` to deposit.
function _updateAssetsForDeposit(uint256 assets) internal virtual {
// Document addition of `assets` to `ta` due to deposit.
_totalAssets = _totalAssets + assets;
}
/// @notice Updates asset values for a pending withdrawal.
/// @param assets The amount of `asset()` to withdraw.
function _updateAssetsForWithdrawal(uint256 assets) internal virtual {
// Document removal of `assets` from `ta` due to withdrawal.
_totalAssets = _totalAssets - assets;
}
/// @dev from Multicall
/// @return The central registry.
function _getCentralRegistry()
internal
view
override
returns (ICentralRegistry)
{
return centralRegistry;
}
/// @notice Helper function to check validity of a proposed posting
/// of collateral.
/// @param shares The number of shares to post as collateral from `owner`.
/// @param owner The address of the account posting `shares`
/// as collateral.
function _checkPostCollateral(
uint256 shares,
address owner
) internal view {
_checkZeroAmount(shares);
if (collateralPosted[owner] + shares > balanceOf(owner)) {
_revert(_INSUFFICIENT_LIQUIDITY_SELECTOR);
}
}
/// @notice Helper function to check validity of a proposed removal
/// of collateral.
/// @param shares The number of shares to remove as collateral
/// from `owner`.
/// @param owner The address of the account removing `shares`
/// as collateral.
function _checkRemoveCollateral(
uint256 shares,
address owner
) internal {
_checkZeroAmount(shares);
uint256 collateralOf = collateralPosted[owner];
if (collateralOf < shares) {
_revert(_INSUFFICIENT_LIQUIDITY_SELECTOR);
}
marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balanceOf(owner),
collateralOf,
true
);
}
/// @notice Helper function to prepare for a transfer.
/// @param shares The number of shares to transfer from `owner` to
/// `receiver`.
/// @param receiver The address of the destination account to receive
/// `shares` shares.y
/// @param owner The address of the account transferring `shares`
/// shares from.
function _checkTransfer(
uint256 shares,
address receiver,
address owner
) internal {
_accrueIfNeeded();
_checkZeroAmount(shares);
if (owner == receiver) {
revert BaseCToken__TransferError();
}
uint256 collateralOf = collateralPosted[owner];
// Fails if transfer not allowed.
uint256 collateralRedeemed = marketManager.canTransfer(
address(this),
shares,
owner,
balanceOf(owner),
collateralOf,
collateralOf > 0 ? true : false
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
_beforeTransferAction(shares, receiver, owner);
}
/// @notice Returns the total assets invariant, any pending rewards for
/// depositors and other values to process a withdrawal.
/// @param assets The amount of the underlying asset to withdraw.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @param ta The current total amount of assets inside this vault.
/// @return balance The balance of shares `owner`.
function _checkRedemption(
uint256 assets,
address owner,
uint256 ta
) internal view returns (uint256 balance) {
_checkZeroAmount(assets);
// Check whether `assets` is above their allowed redemption limit.
if (assets > _convertToAssets(balance = balanceOf(owner), ta)) {
_revert(_INSUFFICIENT_LIQUIDITY_SELECTOR);
}
_checkAssetsHeld(assets);
}
/// @notice Checks to make sure an action is not an empty action.
function _checkZeroAmount(uint256 assets) internal pure {
/// @solidity memory-safe-assembly
assembly {
if iszero(assets) {
mstore(0x00, 0xc0883a55) // Revert BaseCToken__ZeroAmount().
// Return bytes 29-32 for the selector.
revert(0x1c, 0x04)
}
}
}
/// @notice An optional set of instructions to check before processing
/// a redemption of assets.
function _checkAssetsHeld(uint256 /* assets */) internal view virtual {}
/// @dev Checks whether the caller has sufficient permissioning.
function _checkDaoPermissions() internal view {
if (!centralRegistry.hasDaoPermissions(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
}
/// @dev Checks whether the caller has sufficient permissioning.
function _checkElevatedPermissions() internal view {
if (!centralRegistry.hasElevatedPermissions(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function _mulDivUp(
uint256 x,
uint256 y,
uint256 d
) internal pure returns (uint256 z) {
z = FixedPointMathLib.mulDivUp(x, y, d);
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function _mulDiv(
uint256 x,
uint256 y,
uint256 d
) internal pure returns (uint256 z) {
z = FixedPointMathLib.mulDiv(x, y, d);
}
/// INTERNAL HOOK FUNCTIONS WHICH MAY BE OVERRIDDEN ///
/// @notice An optional set of instructions to execute before processing
/// a deposit of `receiver`'s shares.
function _afterDepositAction(uint256, address) internal virtual {}
/// @notice An optional set of instructions to execute before processing
/// a withdrawal of `owners`'s shares.
function _beforeWithdrawAction(uint256, address) internal virtual {}
/// @notice An optional set of instructions to execute before processing
/// a transfer of `owner`'s shares to `receiver`.
function _beforeTransferAction(uint256, address, address) internal virtual {}
/// @notice An optional set of instructions to execute before processing
/// liquidation of `account`'s collateral.
function _beforeLiqAction(uint256, address, address) internal virtual {}
}
// contracts/market/token/BaseCTokenWithYield.sol
abstract contract BaseCTokenWithYield is BaseCToken {
/// CONSTANTS ///
/// @notice The maximum length of time between vesting periods.
/// @dev Though this is inherited by both `BorrowableCToken` and
/// `StrategyCToken` it is only primarily interacted with by
/// `StrategyCToken` this is because `vestingPeriod` is equal to
/// `ADJUSTMENT_RATE` inside the attached `dynamicIRM` which is
/// currently set to always be 10 minutes. This means we have this
/// maximum value check and `vestingPeriod` mainly to create a
/// consistent interface for frontends or other data aggregators
/// to query.
uint256 internal constant _MAXIMUM_VESTING_PERIOD = 3 days;
/// STORAGE ///
/// @notice The period of time harvested rewards are vested over,
/// in seconds.
/// @dev See `_MAXIMUM_VESTING_PERIOD` dev comment for information on how
/// this is only interacted with by `StrategyCToken` and not
/// `BorrowableCToken`.
uint256 public vestingPeriod;
/// @dev Internal packed vesting data:
/// `StrategyCToken` Bits Layout:
/// - [0..127] `VESTING_RATE`.
/// - [128..191] `VEST_END`.
/// - [192..255] `LAST_VEST`.
///
/// `BorrowableCToken` Bits Layout:
/// - [0..95] `VESTING_RATE`.
/// - [96..135] `VEST_END`.
/// - [136..175] `LAST_VEST`.
/// - [176..255] Market `DEBT_INDEX`.
uint256 internal _vestingData;
/// ERRORS ///
error BaseCTokenWithYield__InvalidVestingPeriod();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
/// @param asset_ The address of the underlying asset for this cToken.
/// @param mm The address of the MarketManager which manages liquidity
/// positions between linked cTokens inside a joint market.
/// @param vestingPeriod_ The length of time a vesting period will last,
/// in seconds.
constructor(
ICentralRegistry cr,
IERC20 asset_,
address mm,
uint256 vestingPeriod_
) BaseCToken(cr, asset_, mm) {
_checkVestingPeriod(vestingPeriod_);
vestingPeriod = vestingPeriod_;
}
/// INTERNAL FUNCTIONS ///
/// @notice Validates whether `newPeriod` is a valid value for
/// `vestingPeriod`.
function _checkVestingPeriod(uint256 newPeriod) internal pure {
if (newPeriod > _MAXIMUM_VESTING_PERIOD || newPeriod == 0) {
revert BaseCTokenWithYield__InvalidVestingPeriod();
}
}
/// @notice Returns the total amount of the underlying asset in the vault,
/// including pending rewards that are vested.
/// @return r The total number of underlying assets.
function _getTotalAssets() internal view override returns (uint256 r) {
r = _totalAssets + _assetsToVest();
}
/// @notice Calculates pending assets that have been vested.
/// @dev If there are no pending assets or the vesting period has ended,
/// it returns 0.
/// @return The calculated pending assets to vest.
function _assetsToVest() internal view virtual returns (uint256);
}
// contracts/market/token/BorrowableCToken.sol
contract BorrowableCToken is BaseCTokenWithYield {
/// CONSTANTS ///
/// @notice Maximum percentage fee that can be taken from interest accrued
/// from outstanding debt, in `basis points`.
/// @dev 6000 = 60%.
uint256 public constant MAX_INTEREST_ACCRUAL_FEE = 6000;
/// @notice Percentage (%) fee on loan taken during a flashloan, in `BPS`.
/// @dev 4 bps = 0.04%.
uint256 public constant FLASHLOAN_FEE = 4;
/// @dev Mask of `VESTING_RATE` entry in `_vestingData`.
uint256 internal constant _BITMASK_VESTING_RATE = (1 << 96) - 1;
/// @dev The bit position of `VEST_END` in `_vestingData`.
uint256 internal constant _BITPOS_VEST_END = 96;
/// @dev The bit position of `LAST_VEST` in `_vestingData`.
uint256 internal constant _BITPOS_LAST_VEST = 136;
/// @dev The bit position of `DEBT_INDEX` in `_vestingData` and `_debtOf`.
uint256 internal constant _BITPOS_DEBT_INDEX = 176;
/// @dev `bytes4(keccak256(bytes("BorrowableCToken__InvalidParameter()")))`
uint256 internal constant _INVALID_PARAMETER_SELECTOR = 0x8b5fe5a3;
/// STORAGE ///
/// @notice Address of the current Interest Rate Model used to determine
/// interest paid by borrowers to lenders for outstanding debt.
IDynamicIRM public IRM;
/// @notice The amount of `asset` that has been borrowed as outstanding
/// debt, in assets.
/// @dev We do not need to worry about uint240 overflow here since we
/// limit debt caps to type(uint136).max in the Market Manager.
uint240 public marketOutstandingDebt;
/// @notice The portion of interest paid by borrowers that goes to the
/// protocol, in `BPS`.
uint16 public interestFee;
/// @notice Active debt information associated with an account.
/// @dev Bits Layout:
/// - [0..175] Account `DEBT`.
/// - [176..255] Account `DEBT_INDEX`.
mapping(address => uint256) internal _debtOf;
/// EVENTS ///
event DebtAccrued(uint256 newDebtAssets, uint256 protocolFeeAssets);
event RatesAdjusted(uint256 debtPerSecond, uint256 nextAdjustment);
event Borrow(uint256 assets, uint256 debtAssetsOwed, address account);
event Repay(uint256 assets, uint256 debtAssetsOwed, address payer, address account);
event Flashloan(uint256 assets, uint256 assetsFee, address account);
event BadDebtRecognized(uint256 assets, address liquidator);
event NewIRM(address oldIRM, address newIRM, uint256 newVestingPeriod);
event NewInterestFee(uint256 oldInterestFee, uint256 newInterestFee);
event ExcessRecovered(uint256 assets, address recipient);
/// ERRORS ///
error BorrowableCToken__CollateralPositionActive();
error BorrowableCToken__DebtPositionActive();
error BorrowableCToken__InvalidParameter();
error BorrowableCToken__InsufficientAssetsHeld();
error BorrowableCToken__DepositsNotInitialized();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
/// @param asset_ The address of the underlying asset for this cToken.
/// @param mm The address of the MarketManager which manages liquidity
/// positions between linked cTokens inside a joint market.
/// @param IRM_ The interest rate model to determine interest
/// paid by borrowers to lenders for outstanding debt.
constructor(
ICentralRegistry cr,
IERC20 asset_,
address mm,
address IRM_
) BaseCTokenWithYield(cr, asset_, mm, IDynamicIRM(IRM_).ADJUSTMENT_RATE()) {
// We configure `vestingRate` via both `BaseCTokenWithYield()` and
// `_setIRM()` but this is only for frontends on onchain contracts to
// call, its more efficient for us to call `ADJUSTMENT_RATE` inside
// `IRM` to avoid an sLOAD cost on every adjustment period.
_setIRM(IDynamicIRM(IRM_));
// Assign the portion of interest paid by borrowers that goes to the
// protocol.
_setInterestFee(centralRegistry.defaultProtocolInterestFee());
}
/// @notice Returns the current vesting yield information.
/// @return vestingRate % per second in `asset()`.
/// @return vestingEnd When the current vesting period ends and interest
/// rates paid will update.
/// @return lastVestingClaim Last time pending vested yield was claimed.
/// @return debtIndex The current market debt index.
function getYieldInformation() external view nonReadReentrant returns (
uint256 vestingRate,
uint256 vestingEnd,
uint256 lastVestingClaim,
uint256 debtIndex
) {
// Cache `_vestingData`, the packed vesting data storage value.
uint256 vestingData = _vestingData;
vestingRate = uint96(vestingData);
vestingEnd = uint40(vestingData >> _BITPOS_VEST_END);
lastVestingClaim = uint40(vestingData >> _BITPOS_LAST_VEST);
debtIndex = uint80(vestingData >> _BITPOS_DEBT_INDEX);
}
/// @notice Accrues pending interest and updates the interest rate
/// model (`IRM`) used by this borrowableCToken.
/// @dev Admin function to update the interest rate model.
/// Emits a {NewIRM} event.
/// @param newIRM The new interest rate model to determine interest
/// paid by borrowers to lenders for outstanding debt.
function setIRM(address newIRM) external nonReentrant {
_checkElevatedPermissions();
// Accrue interest if needed.
_accrueIfNeeded();
// Validate that the adjustment rate has not changed from the previous
// one, which would go against user assumptions.
if (IDynamicIRM(newIRM).ADJUSTMENT_RATE() != vestingPeriod) {
revert BaseCTokenWithYield__InvalidVestingPeriod();
}
_setIRM(IDynamicIRM(newIRM));
}
/// @notice Accrues pending interest and updates the fee that the protocol
/// takes on interest paid by borrowers.
/// @dev Admin function to update `interestFee`.
/// Emits a {NewInterestFee} event.
/// @param newInterestFee The portion of interest paid by borrowers that
/// goes to the protocol.
function setInterestFee(uint256 newInterestFee) external nonReentrant {
_checkElevatedPermissions();
// Accrue interest if needed.
_accrueIfNeeded();
_setInterestFee(newInterestFee);
}
/// @notice Borrows underlying tokens from lenders, based on collateral
/// posted inside this market by the caller.
/// @dev Updates pending interest before executing the borrow.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account who will receive the borrowed assets.
function borrow(uint256 assets, address receiver) external nonReentrant {
// Accrue interest if needed.
_accrueIfNeeded();
// Reverts if borrow not allowed.
// Notifies the Market Manager that a user is taking on more debt,
// and to pause user redemptions for 20 minutes.
marketManager.canBorrowWithNotify(
address(this),
assets,
msg.sender,
marketOutstandingDebt + assets
);
_borrow(assets, receiver, msg.sender);
}
/// @notice Used by a delegated user to borrow underlying tokens
/// from lenders, based on collateral posted inside this market
/// by `account`.
/// @dev Updates pending interest before executing the borrow.
/// NOTE: Be careful who you approve here!
/// Not only can they take borrowed funds, but, they can delay
/// repayment through repeated borrows preventing withdrawal.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account who will receive the borrowed assets.
/// @param owner The account who will have their assets borrowed
/// against.
function borrowFor(
uint256 assets,
address receiver,
address owner
) external nonReentrant {
_checkDelegate(owner, msg.sender);
// Accrue interest if needed.
_accrueIfNeeded();
// Reverts if borrow not allowed.
// Notifies the Market Manager that a user is taking on more debt,
// and to pause user redemptions for 20 minutes.
marketManager.canBorrowWithNotify(
address(this),
assets,
owner,
marketOutstandingDebt + assets
);
_borrow(assets, receiver, owner);
}
/// @notice Used by a Position Manager contract to borrow assets from
/// lenders, based on collateralized shares by `account` to
/// perform a complex action.
/// @dev Only Position Manager contract can call this function.
/// Updates pending interest before executing the borrow.
/// @param assets The amount of the underlying asset to borrow.
/// @param action Instructions for a leverage action containing:
/// borrowableCToken Address of the borrowableCToken that
/// will be borrowed from and assets
/// swapped into `cToken` asset.
/// borrowAssets The amount borrowed from
/// `borrowableCToken`, in assets.
/// cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// swapAction Swap action instructions converting debt
/// asset into collateral asset to facilitate
/// leveraging.
/// auxData Optional auxiliary data for execution of a
/// leverage action.
/// @param owner The account address to borrow on behalf of.
function borrowForPositionManager(
uint256 assets,
address owner,
IPositionManager.LeverageAction memory action
) external nonReentrant {
if (!marketManager.isPositionManager(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
// Accrue interest if needed.
// This generally is a redundant check due to interest accrual
// done inside `checkSlippage` modifier inside position manager
// contracts, but we keep this check in for invariant
// protection in the case of a incorrectly implemented contract.
_accrueIfNeeded();
// Notifies the Market Manager that a user is taking on more debt,
// and to pause user redemptions for 20 minutes.
marketManager.notifyBorrow(address(this), owner);
_borrow(assets, msg.sender, owner);
// Callback to Position Manager to execute remaining leverage logic.
IPositionManager(msg.sender).onBorrow(
address(this),
assets,
owner,
action
);
// Fail if terminal position is not allowed with no additional
// adjustment.
marketManager.canBorrow(
address(this),
0,
owner,
marketOutstandingDebt
);
}
/// @notice Repays outstanding debt to lenders, freeing up their
/// collateral posted inside this market.
/// @dev Updates interest before executing the repayment.
/// @param assets The amount to repay, or 0 for the full outstanding
/// amount.
function repay(uint256 assets) external nonReentrant {
_repay(assets, msg.sender, msg.sender);
}
/// @notice Repays outstanding debt to lenders, on behalf of `owner`,
/// freeing up their collateral posted inside this market.
/// @dev Updates pending interest before executing the repay.
/// @param assets The amount to repay, or 0 for the full outstanding
/// amount.
/// @param owner The account address to repay on behalf of.
function repayFor(uint256 assets, address owner) external nonReentrant {
_repay(assets, msg.sender, owner);
}
/// @notice Liquidates `accounts`' collateral by repaying `amount` debt
/// and transferring the liquidated collateral to the liquidator.
/// @dev Updates pending interest before executing the liquidation.
/// @param debtAmounts The amounts of outstanding debt the liquidator
/// wishes to repay, in underlying assets, empty if
/// intention is to liquidate maximum amount possible
/// for each account.
/// @param accounts The addresses of the accounts to be liquidated.
/// @param collateralToken The market in which to seize collateral
/// from `accounts`.
function liquidateExact(
uint256[] calldata debtAmounts,
address[] calldata accounts,
address collateralToken
) external nonReentrant {
uint256 numAccounts = accounts.length;
if (numAccounts != debtAmounts.length) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
_liquidate(
debtAmounts,
msg.sender,
accounts,
collateralToken,
numAccounts,
true
);
}
/// @notice Liquidates `accounts` for as much collateral as possible by
/// repaying debt and transferring the liquidated collateral
/// to the liquidator.
/// @dev Updates pending interest before executing the liquidation.
/// @param accounts The addresses of the accounts to be liquidated.
/// @param collateralToken The market in which to seize collateral
/// from `accounts`.
function liquidate(
address[] calldata accounts,
address collateralToken
) external nonReentrant {
uint256 numAccounts = accounts.length;
// `debtAmounts` array is empty since the max amount possible
// will be liquidated.
uint256[] memory debtAmounts = new uint256[](numAccounts);
_liquidate(
debtAmounts,
msg.sender,
accounts,
collateralToken,
numAccounts,
false
);
}
/// @notice Lends a caller `assets` for a transaction to execute
/// desired programmatic logic, full return of lent
/// assets + a fee by the end of the transaction is
/// required.
/// @param assets The amount of `asset()` loaned during the flashloan.
/// @param data Arbitrary calldata passed to flashloan callback to execute
/// desired action during the flashloan.
function flashLoan(uint256 assets, bytes calldata data) external {
_accrueIfNeeded();
_checkZeroAmount(assets);
if (assets > _asset.balanceOf(address(this))) {
revert BorrowableCToken__InsufficientAssetsHeld();
}
address token = address(_asset);
uint256 fee = flashFee(assets);
uint256 assetsReturned = assets + fee;
SafeTransferLib.safeTransfer(token, msg.sender, assets);
IFlashLoan(msg.sender).onFlashLoan(assets, assetsReturned, data);
SafeTransferLib.safeTransferFrom(
token,
msg.sender,
address(this),
assetsReturned
);
_totalAssets = _totalAssets + fee;
emit Flashloan(assets, fee, msg.sender);
}
/// @notice Updates pending interest and then returns the current
/// market-wide outstanding debt.
/// @dev Used for third party integrations.
/// @return result Total market-wide outstanding debt of asset(), with
/// pending interest applied.
function marketOutstandingDebtUpdated()
external
nonReentrant
returns (uint256 result)
{
// Accrue interest if needed.
_accrueIfNeeded();
result = marketOutstandingDebt;
}
/// @notice Updates pending interest and returns the current outstanding
/// debt owed by `account`.
/// @dev Used for third party integrations.
/// @param account The address whose debt balance should be calculated.
/// @return result The current outstanding debt of `account`, with pending
/// interest applied.
function debtBalanceUpdated(
address account
) external nonReentrant returns (uint256 result) {
// Accrue interest if needed.
_accrueIfNeeded();
result = debtBalance(account);
}
/// @notice Recovers any accumulated excess underlying from rounding or
/// unsolicited donations, to the DAO address.
/// @dev Does not modify `_totalAssets` or any accounting to avoid
/// invariant manipulation.
/// Computed as:
/// debtPlusBalance = marketOutstandingDebt + underlyingBalance
/// excess = debtPlusBalance - totalAssets.
/// Requires DAO permissions.
function skim() external nonReentrant {
_checkDaoPermissions();
uint256 excess = skimAvailable();
address daoAddress = centralRegistry.daoAddress();
SafeTransferLib.safeTransfer(asset(), daoAddress, excess);
emit ExcessRecovered(excess, daoAddress);
}
/// PUBLIC FUNCTIONS ///
/// @notice Returns the amount of excess underlying that can be safely
/// recovered without impacting user accounting.
/// @dev Computed as:
/// marketOutstandingDebt + underlyingBalance - totalAssets.
/// @return excess The recoverable excess underlying amount.
/// Reverts with BaseCToken__ZeroAmount() if none.
function skimAvailable() public view returns (uint256 excess) {
uint256 cachedAssets = _totalAssets;
uint256 debtPlusBalance =
marketOutstandingDebt + IERC20(_asset).balanceOf(address(this));
if (debtPlusBalance <= cachedAssets) {
revert BaseCToken__ZeroAmount();
}
excess = debtPlusBalance - cachedAssets;
}
/// @notice Get a snapshot of the cToken and `account` data.
/// @dev Used by marketManager to more efficiently perform
/// liquidity checks.
/// NOTE: Does not accrue pending interest as part of the call.
/// @param account The address of the account to snapshot.
/// @return result The account snapshot of `account`.
function getSnapshot(
address account
) public view override returns (AccountSnapshot memory result) {
uint256 outstandingDebt = debtBalance(account);
result.asset = address(this);
result.underlying = address(_asset);
result.decimals = decimals();
result.isCollateral = outstandingDebt > 0 ? false : true;
result.collateralPosted = collateralPosted[account];
result.debtBalance = outstandingDebt;
}
/// @notice Returns the current debt balance for `account`.
/// @dev Note: Pending interest is not applied in this calculation.
/// @param account The address whose debt balance should be calculated.
/// @return r The current outstanding debt balance of `account`.
function debtBalance(address account) public view returns (uint256 r) {
// Cache `_debtOf`, the packed account active debt storage value.
uint256 debtOf = _debtOf[account];
uint256 outstandingDebt = uint176(debtOf);
// If theres no outstanding debt, can return immediately with 0.
if (outstandingDebt == 0) {
return r;
}
// Calculate `account` active debt balance using:
// `(Account's outstanding debt * Market's `DEBT_INDEX`) /
// Account's `DEBT_INDEX``.
r = _mulDivUp(
outstandingDebt,
uint80(_vestingData >> _BITPOS_DEBT_INDEX),
uint80(debtOf >> _BITPOS_DEBT_INDEX)
);
}
/// @notice The fee to be charged for a given flashloan.
/// @param assets The amount of `asset()` lent during the flashloan.
/// return The assets of `asset()` to be charged for the flashloan.
function flashFee(uint256 assets) public pure returns (uint256 fee) {
fee = _mulDivUp(assets, FLASHLOAN_FEE, BPS);
}
/// @notice Gets balance of borrowable assets held by this
/// borrowableCToken contract.
/// @dev This excludes changes in assets by the current transaction,
/// if any.
/// @return result The quantity of borrowable assets held by the market.
function assetsHeld() public view returns (uint256 result) {
uint256 currentAssets = _totalAssets;
if (currentAssets == 0) {
revert BorrowableCToken__DepositsNotInitialized();
}
// We add _BASE_UNDERLYING_RESERVE to the calculation to ensure that
// the market never actually runs out of assets and may introduce
// invariant manipulation.
// This also acts as a protective mechanism against trying to
// manipulate marketOutstandingDebt above total underlying assets
// inside the system since there will always be at least
// _BASE_UNDERLYING_RESERVE excess inside the market.
result = currentAssets - marketOutstandingDebt - _BASE_UNDERLYING_RESERVE;
}
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return result Whether this token is borrowable or not.
function isBorrowable() public pure override returns (bool result) {
result = true;
}
/// INTERNAL FUNCTIONS ///
/// @notice Executes borrowing of assets for `account` from lenders.
/// @dev Emits a {Borrow} event.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account receiving the borrowed assets.
/// @param owner The account borrowing assets.
function _borrow(
uint256 assets,
address receiver,
address owner
) internal {
_checkZeroAmount(assets);
_checkAssetsHeld(assets);
// Cannot borrow if `account` already has posted collateral in this
// market.
if (collateralPosted[owner] > 0) {
revert BorrowableCToken__CollateralPositionActive();
}
// Calculate current account debt then add `assets`.
// Then update account exchange rate, and total borrow balances.
uint256 debtOf = debtBalance(owner) + assets;
_setDebtOf(
owner,
uint176(debtOf),
uint80(_vestingData >> _BITPOS_DEBT_INDEX)
);
marketOutstandingDebt = uint240(marketOutstandingDebt + assets);
// Transfer underlying to `receiver`.
SafeTransferLib.safeTransfer(asset(), receiver, assets);
emit Borrow(assets, debtOf, owner);
}
/// @notice Repays an outstanding loan of `account` through repayment
/// by `payer`, who usually is themselves.
/// @dev Emits a {Repay} event.
/// @param assets The amount the payer wishes to repay,
/// or 0 for the full outstanding amount.
/// @param payer The address paying down the account debt.
/// @param owner The account with the debt being paid down.
/// @return The assets of underlying token debt repaid for `account`.
function _repay(
uint256 assets,
address payer,
address owner
) internal returns (uint256) {
// Accrue interest if needed.
_accrueIfNeeded();
// Cache how much the account has to save gas.
uint256 debtOf = debtBalance(owner);
// If assets == 0, repay max; assets = debtOf.
assets = assets == 0 ? debtOf : assets;
_checkZeroAmount(assets);
// Validate repayment amount is not excessive.
if (assets > debtOf) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
SafeTransferLib.safeTransferFrom(asset(), payer, address(this), assets);
// Validate that the payer is allowed to repay the loan, then update
// account data.
marketManager.canRepayWithReview(
address(this),
debtOf = debtOf - assets,
asset(),
decimals(),
owner
);
_setDebtOf(
owner,
uint176(debtOf),
uint80(_vestingData >> _BITPOS_DEBT_INDEX)
);
// We round user debt in favor of the protocol to prevent exchange
// rate manipulation, as a result in some cases the last user cannot
// fully repay their debt.
if (marketOutstandingDebt < assets) {
marketOutstandingDebt = 0;
} else {
marketOutstandingDebt = uint240(marketOutstandingDebt - assets);
}
emit Repay(assets, debtOf, payer, owner);
return assets;
}
/// @notice Facilitates a liquidator liquidating the borrowers collateral
/// by repaying a portion of their debt. The collateral seized
/// is transferred to the liquidator.
/// @dev Emits {Repay} and {Liquidated} events.
/// @param debtAmounts The amounts of outstanding debt the liquidator
/// wishes to repay, in underlying assets, empty if
/// intention is to liquidate maximum amount possible
/// for each account.
/// @param liquidator The address repaying the borrow and seizing
/// collateral.
/// @param accounts The accounts to be liquidated.
/// @param collateralToken The market in which to seize collateral from
/// the account.
/// @param numAccounts The number of accounts to be potentially
/// liquidated.
/// @param exactAmount Whether a specific amount of debt token assets
/// should be liquidated inputting false will attempt
/// to liquidate the maximum amount possible.
function _liquidate(
uint256[] memory debtAmounts,
address liquidator,
address[] calldata accounts,
address collateralToken,
uint256 numAccounts,
bool exactAmount
) internal {
// Cannot have debt and collateral in the same token, so can revert
// immediately if someone tries.
if (collateralToken == address(this)) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Accrue interest if needed.
_accrueIfNeeded();
IMarketManager.LiqResult memory result;
// Fails if liquidation not allowed, trying to repay too much debt
// will revert.
(result, debtAmounts) = marketManager.canLiquidate(
debtAmounts,
liquidator,
accounts,
IMarketManager.LiqAction({
collateralToken: collateralToken,
debtToken: address(this),
numAccounts: numAccounts,
liquidateExact: exactAmount,
liquidatedShares: 0,
debtRepaid: 0,
badDebt: 0
})
);
SafeTransferLib.safeTransferFrom(
asset(),
liquidator,
address(this),
result.debtRepaid
);
uint80 cachedDebtIndex = uint80(_vestingData >> _BITPOS_DEBT_INDEX);
uint256 debtAmount;
uint256 debtOf;
address account;
for (uint256 i; i < numAccounts; ++i) {
// Cache the liquidation repayment amount.
debtAmount = debtAmounts[i];
// If theres no debt to repay for this user can
// skip them.
if (debtAmount == 0) {
continue;
}
account = accounts[i];
// Calculate the new `account` outstanding debt, then update the
// account's debt balance and debt index value.
// Update the account and market outstanding debt balance data.
debtOf = debtBalance(account) - debtAmount;
_setDebtOf(
account,
uint176(debtOf),
cachedDebtIndex
);
emit Repay(debtAmount, debtOf, liquidator, account);
}
// We need to update marketOutstandingDebt for the total debt repaid
// by the liquidator, plus the bad debt being realized. We can reuse
// debtRepaid variable since the original debt repayment value
// was already used earlier.
result.debtRepaid += result.badDebtRealized;
if (marketOutstandingDebt < result.debtRepaid) {
// We round user debt in favor of the protocol to prevent exchange
// rate manipulation, as a result in some cases the last user
// cannot fully repay their debt.
marketOutstandingDebt = 0;
} else {
marketOutstandingDebt =
uint240(marketOutstandingDebt - result.debtRepaid);
}
// Update total assets to recognize that lenders wont be getting
// `result.badDebtRealized` back due to realized bad debt.
// Emit corresponding event recognizing bad debt.
if (result.badDebtRealized > 0) {
uint256 ta = _totalAssets;
if (ta < result.badDebtRealized + _BASE_UNDERLYING_RESERVE) {
revert BorrowableCToken__InsufficientAssetsHeld();
}
_totalAssets = ta - result.badDebtRealized;
emit BadDebtRecognized(result.badDebtRealized, liquidator);
}
ICToken(collateralToken).seize(
result.liquidatedShares,
liquidator,
accounts
);
}
/// @notice Helper function for posting `shares` as collateral
/// for `account` inside this market.
/// @dev Cannot post collateral if `account` already has outstanding
/// debt in this token.
/// Emits {CollateralUpdated} event.
/// May emit {PositionUpdated} event inside Market Manager.
/// @param shares The amount of shares to post as collateral.
/// @param owner The account posting collateral.
function _postCollateral(uint256 shares, address owner) internal override {
// Cannot post collateral if `owner` already has outstanding debt
// in this token.
if (uint176(_debtOf[owner]) > 0) {
revert BorrowableCToken__DebtPositionActive();
}
super._postCollateral(shares, owner);
}
/// @notice Can accrue interest yield, configure next interest accrual
/// period, and updates vesting data, if needed.
/// @dev May emit a {RatesAdjusted} event.
function _accrueIfNeeded() internal override {
// Cache `_vestingData`, the packed vesting data storage value.
uint256 vestingData = _vestingData;
uint256 lastVestingClaim = uint40(vestingData >> _BITPOS_LAST_VEST);
// If no time has passed since `lastVestingClaim` can exit immediately.
if (block.timestamp == lastVestingClaim) {
return;
}
uint256 rate = uint96(vestingData);
uint256 vestingEnd = uint40(vestingData >> _BITPOS_VEST_END);
uint256 marketDebtIndex = uint80(vestingData >> _BITPOS_DEBT_INDEX);
uint256 outstandingDebt = marketOutstandingDebt;
uint256 cachedTa = _totalAssets;
uint256 assetsToVest = _assetsToVest(
rate,
outstandingDebt,
vestingEnd,
lastVestingClaim
);
// Check if it is time to start a new vesting period.
if (block.timestamp >= vestingEnd) {
// Update `lastVestingClaim`, to `vestingEnd` so we can vest any
// pending assets from the new accrual period.
lastVestingClaim = vestingEnd;
uint256 adjustmentRate;
// Calculate the new interest rate for borrowers, in seconds.
(rate, adjustmentRate) = IRM.adjustedBorrowRate(
assetsHeld(),
outstandingDebt + assetsToVest
);
// The multiplication logic here is to round down to
// discrete `adjustmentRate` cycles, e.g. if block.timestamp is 3
// `adjustmentRate`'s ahead then begin vesting all of them for
// users at once.
adjustmentRate = (((block.timestamp - vestingEnd) /
adjustmentRate) * adjustmentRate) + adjustmentRate;
vestingEnd = vestingEnd + adjustmentRate;
emit RatesAdjusted(rate, vestingEnd);
// Check if theres new yield to be vested from the new vesting
// period, which could happen if the previous vesting period ended
// and block.timestamp extends into the new vesting period.
assetsToVest += _assetsToVest(
rate,
outstandingDebt + assetsToVest,
vestingEnd,
lastVestingClaim
);
}
// Calculate any protocol fee on `assetsToVest`, in assets.
// If theres fees we need to mint new shares for the protocol.
uint256 protocolFee = _mulDivUp(assetsToVest, interestFee, BPS);
if (protocolFee > 0) {
// We can calculate how many shares the protocol should receive
// from its fee on assetsToVest by using the formula:
// (fee * totalSupply) / (totalAssets + assetsToVest - fee).
// This means that that shares minted will result in an exchange
// rate matching the amount of vested assets lenders should
// benefit from.
uint256 protocolFeeShares = FixedPointMathLib.fullMulDivUp(
protocolFee,
totalSupply(),
cachedTa + assetsToVest - protocolFee
);
// Cache `daoAddress` then mint shares to dao operator address.
address daoAddress = centralRegistry.daoAddress();
_mint(daoAddress, protocolFeeShares);
_afterDepositAction(protocolFeeShares, daoAddress);
}
// Vest pending assets, if there is any.
if (assetsToVest > 0) {
// `assetsToVest` is new outstanding debt in assets so we
// need to divide by `outstandingDebt` so its in % form.
// Rounding up here can cause individual user debt to be increased
// more heavily than expected when a cToken has extremely low
// borrow utilization, this is intentional.
marketDebtIndex =
_mulDivUp(assetsToVest, marketDebtIndex, outstandingDebt)
+ marketDebtIndex;
// Update marketOutstandingDebt invariant with vested assets.
marketOutstandingDebt = uint240(outstandingDebt + assetsToVest);
// Update _totalAssets based on new assets recognized by protocol.
_totalAssets = cachedTa + assetsToVest;
emit DebtAccrued(assetsToVest, protocolFee);
}
assembly {
// Mask `rate` to the lower 96 bits, in case the upper bits
// somehow are not clean.
rate := and(rate, _BITMASK_VESTING_RATE)
// Equals `rate | (vestingEnd << _BITPOS_VEST_END) |
// block.timestamp << _BITPOS_LAST_VEST | marketDebtIndex`.
vestingData := or(
rate,
or(
or(
shl(_BITPOS_VEST_END, vestingEnd),
shl(_BITPOS_LAST_VEST, timestamp())
),
shl(_BITPOS_DEBT_INDEX, marketDebtIndex)
)
)
// Update packed `_vestingData` based on new vesting config.
sstore(_vestingData.slot, vestingData)
}
}
/// @notice Updates the interest rate model (`IRM`) used
/// by this borrowableCToken.
/// @dev Emits a {NewIRM} event.
/// @param newIRM The new interest rate model to determine interest paid
/// by borrowers to lenders for outstanding debt.
function _setIRM(IDynamicIRM newIRM) internal {
// Ensure we are switching to an actual Interest Rate Model.
if (
!ERC165Checker.supportsInterface(
address(newIRM),
type(IDynamicIRM).interfaceId
)
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Cache the current interest rate model for event emission.
address oldIRM = address(IRM);
// Set new interest rate model and compound rate.
IRM = newIRM;
uint256 newPeriod = newIRM.ADJUSTMENT_RATE();
vestingPeriod = newPeriod;
emit NewIRM(oldIRM, address(newIRM), newPeriod);
}
/// @notice Updates the fee that the protocol takes on interest paid
/// by borrowers.
/// @dev Emits a {NewInterestFee} event.
/// @param newInterestFee The portion of interest paid by borrowers that
/// goes to the protocol, in `BPS`.
function _setInterestFee(uint256 newInterestFee) internal {
// The DAO cannot take more than `MAX_INTEREST_ACCRUAL_FEE` of
// interest collected.
if (newInterestFee > MAX_INTEREST_ACCRUAL_FEE) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Cache the old interest fee for event emission.
uint256 oldInterestFee = interestFee;
interestFee = uint16(newInterestFee);
emit NewInterestFee(oldInterestFee, interestFee);
}
/// @notice Packs `newOutstandingDebt` with current `marketDebtIndex` to
/// create new packed `_debtOf` for `account`.
/// @param account The account to set `_debtOf` value for.
/// @param newOutstandingDebt The new outstanding debt of `account`.
/// @param marketDebtIndex The current market debt index value.
function _setDebtOf(
address account,
uint176 newOutstandingDebt,
uint80 marketDebtIndex
) internal {
uint256 newDebtOf;
// Cast `newDebtOf` with assembly to avoid redundant masking.
/// @solidity memory-safe-assembly
assembly {
newDebtOf := newOutstandingDebt
// `newDebtOf | marketDebtIndex`.
newDebtOf := or(
newDebtOf,
shl(_BITPOS_DEBT_INDEX, marketDebtIndex)
)
}
_debtOf[account] = newDebtOf;
}
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @dev Emits a {Deposit} event.
/// @param by The account initializing deposits.
function _initializeDeposits(address by) internal override {
// Validate that the interest rate model is linked to this token.
if (IRM.linkedToken() != address(this)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
super._initializeDeposits(by);
// Calculate `_vestingData` invariant to intended start values.
_vestingData = (_vestingData & _BITMASK_VESTING_RATE) |
(block.timestamp << _BITPOS_VEST_END) |
(block.timestamp << _BITPOS_LAST_VEST) |
(WAD << _BITPOS_DEBT_INDEX);
}
/// @notice Calculates pending assets that have been vested.
/// @dev If there are no pending assets or the vesting period has ended,
/// it returns 0.
/// @return assets The calculated pending assets to vest.
function _assetsToVest() internal view override returns (uint256 assets) {
// Cache `_vestingData`, the packed vesting data storage value.
uint256 vestingData = _vestingData;
assets = _assetsToVest(
uint96(vestingData),
marketOutstandingDebt,
uint40(vestingData >> _BITPOS_VEST_END),
uint40(vestingData >> _BITPOS_LAST_VEST)
);
}
/// @notice Calculates pending assets that have been vested.
/// @dev If there are no pending assets or the vesting period has ended,
/// it returns 0.
/// @return assets The calculated pending assets to vest.
function _assetsToVest(
uint256 vestingRate,
uint256 outstandingDebt,
uint256 vestingEnd,
uint256 lastVestingClaim
) internal view returns (uint256 assets) {
// Check whether there are pending assets vesting.
if (vestingRate > 0 && lastVestingClaim < vestingEnd) {
// When calculating pending assets to vest, if the vesting period
// has not ended:
// assets = vestingRate * (block.timestamp - lastVestingClaim).
// If the vesting period has ended:
// assets = vestingRate * (vestingEnd - lastVestingClaim).
// Then in either case:
// Divide the pending yield by `WAD` (1e18) for precision.
assets = _mulDiv(
block.timestamp < vestingEnd
? vestingRate * (block.timestamp - lastVestingClaim)
: vestingRate * (vestingEnd - lastVestingClaim),
outstandingDebt,
WAD
);
}
}
/// @notice Checks whether there is sufficient assets to handle
/// a withdrawal of `assets` based on assets currently held in
/// this contract.
/// @param assets The amount of assets to withdraw which is checked
/// against current assets held in the contract.
function _checkAssetsHeld(uint256 assets) internal view override {
if (assetsHeld() < assets) {
revert BorrowableCToken__InsufficientAssetsHeld();
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ICentralRegistry","name":"cr","type":"address"},{"internalType":"contract IERC20","name":"asset_","type":"address"},{"internalType":"address","name":"mm","type":"address"},{"internalType":"address","name":"IRM_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllowanceOverflow","type":"error"},{"inputs":[],"name":"AllowanceUnderflow","type":"error"},{"inputs":[],"name":"BaseCTokenWithYield__InvalidVestingPeriod","type":"error"},{"inputs":[],"name":"BaseCToken__InsufficientLiquidity","type":"error"},{"inputs":[],"name":"BaseCToken__InvalidMarketManager","type":"error"},{"inputs":[],"name":"BaseCToken__InvariantError","type":"error"},{"inputs":[],"name":"BaseCToken__TransferError","type":"error"},{"inputs":[],"name":"BaseCToken__Unauthorized","type":"error"},{"inputs":[],"name":"BaseCToken__UnsupportedChain","type":"error"},{"inputs":[],"name":"BaseCToken__ZeroAmount","type":"error"},{"inputs":[],"name":"BorrowableCToken__CollateralPositionActive","type":"error"},{"inputs":[],"name":"BorrowableCToken__DebtPositionActive","type":"error"},{"inputs":[],"name":"BorrowableCToken__DepositsNotInitialized","type":"error"},{"inputs":[],"name":"BorrowableCToken__InsufficientAssetsHeld","type":"error"},{"inputs":[],"name":"BorrowableCToken__InvalidParameter","type":"error"},{"inputs":[],"name":"CentralRegistryLib__InvalidCentralRegistry","type":"error"},{"inputs":[],"name":"DepositMoreThanMax","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidPermit","type":"error"},{"inputs":[],"name":"LowLevelCallsHelper__CallFailed","type":"error"},{"inputs":[],"name":"MintMoreThanMax","type":"error"},{"inputs":[],"name":"Multicall__InvalidTarget","type":"error"},{"inputs":[],"name":"Multicall__UnknownCalldata","type":"error"},{"inputs":[],"name":"PermitExpired","type":"error"},{"inputs":[],"name":"PluginDelegable_InvalidParameter","type":"error"},{"inputs":[],"name":"PluginDelegable__DelegatingDisabled","type":"error"},{"inputs":[],"name":"PluginDelegable__Unauthorized","type":"error"},{"inputs":[],"name":"RedeemMoreThanMax","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"TotalSupplyOverflow","type":"error"},{"inputs":[],"name":"WithdrawMoreThanMax","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"}],"name":"BadDebtRecognized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtAssetsOwed","type":"uint256"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"bool","name":"increased","type":"bool"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"CollateralUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDebtAssets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFeeAssets","type":"uint256"}],"name":"DebtAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"approvalIndex","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"DelegateApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"ExcessRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Flashloan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Liquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldIRM","type":"address"},{"indexed":false,"internalType":"address","name":"newIRM","type":"address"},{"indexed":false,"internalType":"uint256","name":"newVestingPeriod","type":"uint256"}],"name":"NewIRM","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldInterestFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newInterestFee","type":"uint256"}],"name":"NewInterestFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nextAdjustment","type":"uint256"}],"name":"RatesAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtAssetsOwed","type":"uint256"},{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"result","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FLASHLOAN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IRM","outputs":[{"internalType":"contract IDynamicIRM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_INTEREST_ACCRUAL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueIfNeeded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetsHeld","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"borrowFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"contract IBorrowableCToken","name":"borrowableCToken","type":"address"},{"internalType":"uint256","name":"borrowAssets","type":"uint256"},{"internalType":"contract ICToken","name":"cToken","type":"address"},{"internalType":"uint256","name":"expectedShares","type":"uint256"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap","name":"swapAction","type":"tuple"},{"internalType":"bytes","name":"auxData","type":"bytes"}],"internalType":"struct IPositionManager.LeverageAction","name":"action","type":"tuple"}],"name":"borrowForPositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"centralRegistry","outputs":[{"internalType":"contract ICentralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"checkNewDelegationDisabled","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"collateralPosted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"debtBalance","outputs":[{"internalType":"uint256","name":"r","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"debtBalanceUpdated","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"depositAsCollateral","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"depositAsCollateralFor","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateUpdated","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getSnapshot","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"isCollateral","type":"bool"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"uint256","name":"debtBalance","type":"uint256"}],"internalType":"struct AccountSnapshot","name":"result","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getSnapshotUpdated","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"isCollateral","type":"bool"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"uint256","name":"debtBalance","type":"uint256"}],"internalType":"struct AccountSnapshot","name":"result","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getYieldInformation","outputs":[{"internalType":"uint256","name":"vestingRate","type":"uint256"},{"internalType":"uint256","name":"vestingEnd","type":"uint256"},{"internalType":"uint256","name":"lastVestingClaim","type":"uint256"},{"internalType":"uint256","name":"debtIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"by","type":"address"}],"name":"initializeDeposits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBorrowable","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"delegate","type":"address"}],"name":"isDelegate","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"address","name":"collateralToken","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"debtAmounts","type":"uint256[]"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"address","name":"collateralToken","type":"address"}],"name":"liquidateExact","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketCollateralPosted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketManager","outputs":[{"internalType":"contract IMarketManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketOutstandingDebt","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketOutstandingDebtUpdated","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isPriceUpdate","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Multicall.MulticallAction[]","name":"calls","type":"tuple[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"postCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"postCollateralFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeemCollateral","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeemCollateralFor","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeemFor","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"removeCollateralFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"repayFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"liquidatedShares","type":"uint256[]"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"seize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setDelegateApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newIRM","type":"address"}],"name":"setIRM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newInterestFee","type":"uint256"}],"name":"setInterestFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skimAvailable","outputs":[{"internalType":"uint256","name":"excess","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userApprovalIndex","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vestingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"contract ICToken","name":"cToken","type":"address"},{"internalType":"uint256","name":"collateralAssets","type":"uint256"},{"internalType":"contract IBorrowableCToken","name":"borrowableCToken","type":"address"},{"internalType":"uint256","name":"repayAssets","type":"uint256"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap[]","name":"swapActions","type":"tuple[]"},{"internalType":"bytes","name":"auxData","type":"bytes"}],"internalType":"struct IPositionManager.DeleverageAction","name":"action","type":"tuple"}],"name":"withdrawByPositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdrawCollateral","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
0x610100604052348015610010575f5ffd5b506040516169d13803806169d183398101604081905261002f91610630565b838383836001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561006e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610092919061068c565b8383838261009f8161035c565b6001600160a01b03908116608052821660c0819052604080516306fdde0360e01b815290516306fdde03916004808201925f929091908290030181865afa1580156100ec573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261011391908101906106b7565b604051602001610123919061077e565b60405160208183030381529060405260029081610140919061081f565b50816001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801561017c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101a391908101906106b7565b6040516020016101b391906108d9565b604051602081830303815290604052600390816101d0919061081f565b50816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023191906108ee565b60ff1660e052608051604051637d5528bd60e01b81526001600160a01b03838116600483015290911690637d5528bd90602401602060405180830381865afa15801561027f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102a3919061090e565b6102c0576040516365c906df60e11b815260040160405180910390fd5b6001600160a01b031660a052506102d890508161038d565b600655506102e991508290506103ba565b6103536080516001600160a01b031663d68dbfe46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034e919061068c565b6104b7565b5050505061092d565b61036d816399011ef160e01b610538565b61038a576040516369b5e45b60e11b815260040160405180910390fd5b50565b6203f48081118061039c575080155b1561038a57604051631961405760e31b815260040160405180910390fd5b6103cb81638ec124b360e01b610538565b6103dc576103dc638b5fe5a361055a565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa15801561043b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061045f919061068c565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a0329060600160405180910390a1505050565b6117708111156104ce576104ce638b5fe5a361055a565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b910160405180910390a15050565b5f61054283610563565b801561055357506105538383610596565b9392505050565b805f526004601cfd5b5f610575826301ffc9a760e01b610596565b8015610590575061058e826001600160e01b0319610596565b155b92915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015610606575060208210155b801561061157505f81115b979650505050505050565b6001600160a01b038116811461038a575f5ffd5b5f5f5f5f60808587031215610643575f5ffd5b845161064e8161061c565b602086015190945061065f8161061c565b60408601519093506106708161061c565b60608601519092506106818161061c565b939692955090935050565b5f6020828403121561069c575f5ffd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156106c7575f5ffd5b81516001600160401b038111156106dc575f5ffd5b8201601f810184136106ec575f5ffd5b80516001600160401b03811115610705576107056106a3565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610733576107336106a3565b60405281815282820160200186101561074a575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518060208401855e5f93019283525090919050565b68021bab93b30b731b2960bd1b81525f6105536009830184610767565b600181811c908216806107af57607f821691505b6020821081036107cd57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561081a57805f5260205f20601f840160051c810160208510156107f85750805b601f840160051c820191505b81811015610817575f8155600101610804565b50505b505050565b81516001600160401b03811115610838576108386106a3565b61084c81610846845461079b565b846107d3565b6020601f82116001811461087e575f83156108675750848201515b5f19600385901b1c1916600184901b178455610817565b5f84815260208120601f198516915b828110156108ad578785015182556020948501946001909201910161088d565b50848210156108ca57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b606360f81b81525f6105536001830184610767565b5f602082840312156108fe575f5ffd5b815160ff81168114610553575f5ffd5b5f6020828403121561091e575f5ffd5b81518015158114610553575f5ffd5b60805160a05160c05160e051615f2f610aa25f395f818161061701528181610f7a015261378101525f818161068401528181610e9301528181610f51015281816115dd0152818161167001528181612c6401528181612ed2015281816136fa0152818161376001528181613e1f01528181614490015281816149910152614c8701525f81816106db0152818161108a0152818161130f01528181611392015281816114b6015281816117c501528181611b8901528181611e1d01528181611ecc01528181611fc00152818161237b01528181612def015281816132be01528181613471015281816135610152818161372b0152818161409a015281816141a401528181614330015281816145da01528181614a640152614c4b01525f81816108e501528181610e0e01528181611aa6015281816120e0015281816124970152818161253d0152818161296b015281816129da0152818161319b0152818161392f01528181613c140152613f720152615f2f5ff3fe608060405234801561000f575f5ffd5b506004361061047a575f3560e01c806372d46ac211610258578063b3d7f6b91161014b578063d4bb0c73116100ca578063e28d591d1161008f578063e28d591d14610ad9578063e6248d5514610af8578063e8bbf5d714610b0b578063ef8b30f714610b2b578063f0c00c4114610b3e578063f411029114610b46575f5ffd5b8063d4bb0c7314610a6f578063d505accf14610a82578063d905777e14610a95578063dd62ed3e14610aa8578063deee770414610ad0575f5ffd5b8063c63d75b611610110578063c63d75b6146106b0578063c6e6f59214610a23578063cd88c07214610a36578063ce96cb7714610a49578063cf6af22d14610a5c575f5ffd5b8063b3d7f6b9146109c4578063b460af94146109d7578063ba087652146109ea578063bdca6723146109fd578063c3c854b614610a10575f5ffd5b806394bf804d116101d7578063a7af467a1161019c578063a7af467a14610970578063a9059cbb14610983578063ab21e62814610996578063ad9d3683146109a9578063b3bffb45146109b1575f5ffd5b806394bf804d1461090757806395d89b411461091a5780639616756e146109225780639e591a4414610935578063a75df49814610948575f5ffd5b80637ecebe001161021d5780637ecebe001461089757806380fd997f146108bc57806385b13080146108c557806387367d71146108d85780638f73dcfa146108e0575f5ffd5b806372d46ac2146108385780637313ee5a1461084b578063775a814a146108545780637ada7a091461085c5780637c0e0c8c1461086f575f5ffd5b806338d52e0f116103705780635722baf3116102ef578063635d9771116102b4578063635d9771146107af578063640fef7b146107da5780636779db5b146107ed5780636e553f651461080057806370a0823114610813575f5ffd5b80635722baf31461075057806357d159d5146107635780635b56d6f5146107765780635c0bfa88146107895780635fec5d0b1461079c575f5ffd5b806345d7b97a1161033557806345d7b97a146106fd5780634b3fd148146107045780634cdad5061461071757806350f2012f1461072a5780635296a4311461073d575f5ffd5b806338d52e0f146106825780633ba0b9a9146106a8578063402d267d146106b057806340c09eba146106c357806341ed2c12146106d6575f5ffd5b80631dd19cb4116103fc578063313ce567116103c1578063313ce567146106105780633237c158146106415780633644e51514610654578063371fd8e61461065c57806338c0f3091461066f575f5ffd5b80631dd19cb41461054a5780631e75db1614610552578063215702561461057d57806323b872dd146105ea5780632f4a61d9146105fd575f5ffd5b80630a28a477116104425780630a28a477146104f75780630f0f54361461050a57806311005b071461051f578063176679671461053257806318160ddd1461053a575f5ffd5b806301e1d1141461047e57806301ffc9a71461049957806306fdde03146104bc57806307a2d13a146104d1578063095ea7b3146104e4575b5f5ffd5b610486610b4e565b6040519081526020015b60405180910390f35b6104ac6104a7366004614f3b565b610b79565b6040519015158152602001610490565b6104c4610bca565b6040516104909190614f90565b6104866104df366004614fa2565b610c5a565b6104ac6104f2366004614fcd565b610c8e565b610486610505366004614fa2565b610cdd565b61051d61051836600461503e565b610cef565b005b61048661052d366004615090565b610d80565b610486600481565b6805345cdf77eb68f44c54610486565b61051d610dcf565b600854610565906001600160a01b031681565b6040516001600160a01b039091168152602001610490565b61059061058b366004615090565b610f0a565b604051610490919081516001600160a01b0390811682526020808401519091169082015260408083015160ff16908201526060808301511515908201526080808301519082015260a0918201519181019190915260c00190565b6104ac6105f83660046150ab565b610fdf565b61048661060b3660046150e9565b611037565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610490565b61051d61064f366004614fa2565b611137565b610486611183565b61051d61066a366004614fa2565b6111ff565b61051d61067d366004615117565b611243565b7f0000000000000000000000000000000000000000000000000000000000000000610565565b6104866112d9565b6104866106be366004615090565b6112ee565b61051d6106d13660046150e9565b611421565b6105657f000000000000000000000000000000000000000000000000000000000000000081565b60016104ac565b61051d6107123660046150e9565b611478565b610486610725366004614fa2565b61156d565b61051d610738366004614fa2565b61157a565b61051d61074b366004615198565b6115b7565b61051d61075e36600461520d565b611781565b610486610771366004615090565b611994565b61051d610784366004614fa2565b6119e2565b61048661079736600461528d565b611a24565b6104ac6107aa3660046152c1565b611a71565b6009546107c2906001600160f01b031681565b6040516001600160f01b039091168152602001610490565b61051d6107e836600461528d565b611b41565b6104866107fb36600461528d565b611c51565b61048661080e3660046150e9565b611c89565b610486610821366004615090565b6387a211a2600c9081525f91909152602090205490565b61048661084636600461528d565b611cd1565b61048660065481565b61051d611d08565b6104ac61086a366004615090565b611d47565b610877611d8e565b604080519485526020850193909352918301526060820152608001610490565b6104866108a5366004615090565b6338377508600c9081525f91909152602090205490565b61048661177081565b61051d6108d3366004615482565b611ddf565b61048661202c565b6105657f000000000000000000000000000000000000000000000000000000000000000081565b6104866109153660046150e9565b61207c565b6104c46120b0565b6104ac610930366004615090565b6120bf565b61051d6109433660046150e9565b61214b565b60095461095d90600160f01b900461ffff1681565b60405161ffff9091168152602001610490565b61048661097e366004614fa2565b612190565b6104ac610991366004614fcd565b61219f565b61051d6109a43660046150e9565b6121f5565b61048661223c565b6104866109bf3660046150e9565b61228a565b6104866109d2366004614fa2565b6122be565b6104866109e536600461528d565b6122d0565b6104866109f836600461528d565b612306565b61051d610a0b366004615618565b61233d565b61051d610a1e3660046156d0565b612459565b610486610a31366004614fa2565b612626565b610486610a4436600461528d565b612655565b610486610a57366004615090565b61268d565b610590610a6a366004615090565b6126aa565b61051d610a7d366004615090565b6126ec565b61051d610a903660046156fc565b6127af565b610486610aa3366004615090565b612931565b610486610ab63660046152c1565b602052637f5e9f20600c9081525f91909152603490205490565b61048660015481565b610486610ae7366004615090565b60056020525f908152604090205481565b610486610b06366004615090565b61294a565b610b1e610b1936600461576d565b6129d6565b60405161049091906157ab565b610486610b39366004614fa2565b612c38565b610486612c45565b610486612d1e565b5f688000000000ab143c065c15610b6c5763ab143c065f526004601cfd5b610b74612d37565b905090565b5f6001600160e01b03198216630934615b60e01b1480610ba957506001600160e01b0319821663b6e300c760e01b145b80610bc457506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610bd99061580e565b80601f0160208091040260200160405190810160405280929190818152602001828054610c059061580e565b8015610c505780601f10610c2757610100808354040283529160200191610c50565b820191905f5260205f20905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b5f688000000000ab143c065c15610c785763ab143c065f526004601cfd5b610bc482610c84612d37565b612d4d565b919050565b5f82602052637f5e9f20600c52335f52816034600c2055815f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa350600192915050565b5f610bc482610cea612d37565b612d80565b688000000000ab143c065c15610d0c5763ab143c065f526004601cfd5b30688000000000ab143c065d815f816001600160401b03811115610d3257610d326152ed565b604051908082528060200260200182016040528015610d5b578160200160208202803683370190505b509050610d6d8133878787875f612da6565b50505f688000000000ab143c065d505050565b6001600160a01b0381165f908152600a60205260408120546001600160b01b038116808303610db0575050919050565b600754610dc790829060b090811c9085901c61317a565b949350505050565b688000000000ab143c065c15610dec5763ab143c065f526004601cfd5b30688000000000ab143c065d610e00613186565b5f610e09612c45565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e68573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8c9190615846565b9050610eb97f00000000000000000000000000000000000000000000000000000000000000008284613220565b604080518381526001600160a01b03831660208201527f88fc2578c4b534418a67792f942c22deab48988e8f00bf87d4f8b0d0a8655772910160405180910390a150505f688000000000ab143c065d565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610f4483610d80565b3083526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016602084015290507f000000000000000000000000000000000000000000000000000000000000000060ff16604083015280610fad576001610faf565b5f5b151560608301526001600160a01b039092165f90815260056020526040902054608082015260a081019190915290565b5f688000000000ab143c065c15610ffd5763ab143c065f526004601cfd5b30688000000000ab143c065d611014828486613260565b61101f84848461338c565b50600190505f688000000000ab143c065d9392505050565b5f688000000000ab143c065c156110555763ab143c065f526004601cfd5b30688000000000ab143c065d336001600160a01b038316148015906110fd5750604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa1580156110d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fb9190615861565b155b1561110f5761110f63471656c5613433565b611119838361343c565b905061112581836134dc565b5f688000000000ab143c065d92915050565b688000000000ab143c065c156111545763ab143c065f526004601cfd5b30688000000000ab143c065d61116a8133613529565b6111748133613616565b5f688000000000ab143c065d50565b5f8061118d610bca565b8051906020012090506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81528160208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015260a081209250505090565b688000000000ab143c065c1561121c5763ab143c065f526004601cfd5b30688000000000ab143c065d6112338133336136b2565b505f688000000000ab143c065d50565b688000000000ab143c065c156112605763ab143c065f526004601cfd5b30688000000000ab143c065d8184811461128157611281638b5fe5a3613433565b6112c58686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525033925088915087905086866001612da6565b505f688000000000ab143c065d5050505050565b5f610b74670de0b6b3a7640000610c84612d37565b60405163699ba8b360e01b81523060048201525f9081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063699ba8b390602401606060405180830381865afa158015611354573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113789190615890565b5050604051637bca031760e11b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f794062e90602401602060405180830381865afa1580156113df573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114039190615861565b158061140c5750805b156114175750919050565b5f195b9392505050565b688000000000ab143c065c1561143e5763ab143c065f526004601cfd5b30688000000000ab143c065d61145481336138fd565b61145e82826139e0565b61146882826134dc565b5f688000000000ab143c065d5050565b688000000000ab143c065c156114955763ab143c065f526004601cfd5b30688000000000ab143c065d6114a9613a32565b6009546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f96492c9903090859033906114f79083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b15801561154c575f5ffd5b505af115801561155e573d5f5f3e3d5ffd5b50505050611468828233613d5a565b5f610bc482610c84612d37565b688000000000ab143c065c156115975763ab143c065f526004601cfd5b30688000000000ab143c065d6115ad81336139e0565b61117481336134dc565b6115bf613a32565b6115c883613e93565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561162a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164e91906158e2565b83111561166e5760405163ab2169c760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000005f61169985612190565b90505f6116a682876158cf565b90506116b3833388613220565b604051637924fd7d60e01b81523390637924fd7d906116dc90899085908a908a906004016158f9565b6020604051808303815f875af11580156116f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061171c91906158e2565b5061172983333084613ea8565b8160045461173791906158cf565b6004556040805187815260208101849052338183015290517fb216ab52d7988a2a0e79070667f92d2ade5e6464ee97984d5983afe3572348269181900360600190a1505050505050565b688000000000ab143c065c1561179e5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630eaa39a960e31b81523060048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637551cd48906044015f604051808303815f87803b15801561180e575f5ffd5b505af1158015611820573d5f5f3e3d5ffd5b508392505f915081905080805b848110156119695789898281811061184757611847615935565b905060200201359250825f03156119615786868281811061186a5761186a615935565b905060200201602081019061187f9190615090565b915061188b83856158cf565b6001600160a01b0383165f908152600560205260409020549094506118b1908490615949565b6001600160a01b0383165f81815260056020908152604080832094909455835187815290810191909152918201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda69060600160405180910390a1611917828985613ef7565b604080518481526001600160a01b038a8116602083015284168183015290517f6ee556dbce23a24ad3b539ee42191a2dd262b16ecb4d0ef20dbeb4bb5a9a23839181900360600190a15b60010161182d565b50826001546119789190615949565b600155505f9250688000000000ab143c069150505d5050505050565b5f688000000000ab143c065c156119b25763ab143c065f526004601cfd5b30688000000000ab143c065d6119c6613a32565b6119cf82610d80565b90505f688000000000ab143c065d919050565b688000000000ab143c065c156119ff5763ab143c065f526004601cfd5b30688000000000ab143c065d611a13613f5d565b611a1b613a32565b61117481613fa9565b5f688000000000ab143c065c15611a425763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c84848460015f614023565b90505f688000000000ab143c065d9392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529092909183917f0000000000000000000000000000000000000000000000000000000000000000169063e6248d5590602401602060405180830381865afa158015611aeb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0f91906158e2565b815260208082019290925260409081015f9081206001600160a01b039095168152939091529091205460ff1692915050565b688000000000ab143c065c15611b5e5763ab143c065f526004601cfd5b30688000000000ab143c065d611b7481336138fd565b611b7c613a32565b6009546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f96492c990309086908590611bca9083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b158015611c1f575f5ffd5b505af1158015611c31573d5f5f3e3d5ffd5b50505050611c40838383613d5a565b5f688000000000ab143c065d505050565b5f688000000000ab143c065c15611c6f5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c848484600180614023565b5f688000000000ab143c065c15611ca75763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd838361343c565b90505f688000000000ab143c065d92915050565b5f688000000000ab143c065c15611cef5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484846001614142565b688000000000ab143c065c15611d255763ab143c065f526004601cfd5b30688000000000ab143c065d611d39613a32565b5f688000000000ab143c065d565b5f688000000000ab143c065c15611d655763ab143c065f526004601cfd5b30688000000000ab143c065d611d7a8261424b565b5060015f688000000000ab143c065d919050565b5f5f5f5f688000000000ab143c065c15611daf5763ab143c065f526004601cfd5b50506007546001600160601b0381169364ffffffffff606083901c81169450608883901c16925060b09190911c90565b688000000000ab143c065c15611dfc5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa158015611e6a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8e9190615861565b611e9f57611e9f63471656c5613433565b611ea7613a32565b60405163463aea7f60e11b81523060048201526001600160a01b0383811660248301527f00000000000000000000000000000000000000000000000000000000000000001690638c75d4fe906044015f604051808303815f87803b158015611f0d575f5ffd5b505af1158015611f1f573d5f5f3e3d5ffd5b50505050611f2e833384613d5a565b6040516318f9a83960e21b815233906363e6a0e490611f579030908790879087906004016159b4565b5f604051808303815f87803b158015611f6e575f5ffd5b505af1158015611f80573d5f5f3e3d5ffd5b5050600954604051630967a76b60e31b81523060048201525f60248201526001600160a01b0386811660448301526001600160f01b0390921660648201527f00000000000000000000000000000000000000000000000000000000000000009091169250634b3d3b5891506084015f604051808303815f87803b158015612005575f5ffd5b505af1158015612017573d5f5f3e3d5ffd5b505050505f688000000000ab143c065d505050565b6004545f90808203612051576040516354e9f59b60e01b815260040160405180910390fd5b60095462012fd19061206c906001600160f01b031683615949565b6120769190615949565b91505090565b5f688000000000ab143c065c1561209a5763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd8383614309565b606060038054610bd99061580e565b604051634b0b3ab760e11b81526001600160a01b0382811660048301525f917f000000000000000000000000000000000000000000000000000000000000000090911690639616756e90602401602060405180830381865afa158015612127573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc49190615861565b688000000000ab143c065c156121685763ab143c065f526004601cfd5b30688000000000ab143c065d61217f8233836136b2565b505f688000000000ab143c065d5050565b5f610bc482600461271061317a565b5f688000000000ab143c065c156121bd5763ab143c065f526004601cfd5b30688000000000ab143c065d6121d4828433613260565b6121de83836143a9565b50600190505f688000000000ab143c065d92915050565b688000000000ab143c065c156122125763ab143c065f526004601cfd5b30688000000000ab143c065d61222881336138fd565b6122328282613529565b6114688282613616565b5f688000000000ab143c065c1561225a5763ab143c065f526004601cfd5b30688000000000ab143c065d61226e613a32565b506009546001600160f01b03165f688000000000ab143c065d90565b5f688000000000ab143c065c156122a85763ab143c065f526004601cfd5b30688000000000ab143c065d61110f82336138fd565b5f610bc4826122cb612d37565b61440d565b5f688000000000ab143c065c156122ee5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f614142565b5f688000000000ab143c065c156123245763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f5f614023565b688000000000ab143c065c1561235a5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa1580156123c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ec9190615861565b6123fd576123fd63471656c5613433565b612405613a32565b5f61240e612d37565b90505f61241c858584614433565b90505f6124298684612d80565b90506124388682333389614478565b612445868287858861451d565b5050505f688000000000ab143c065d505050565b336001600160a01b0383160361248257604051636eef2f3f60e11b815260040160405180910390fd5b604051634b0b3ab760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639616756e90602401602060405180830381865afa1580156124e4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125089190615861565b15612526576040516302d5da9f60e01b815260040160405180910390fd5b60405163e6248d5560e01b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e6248d5590602401602060405180830381865afa15801561258a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125ae91906158e2565b335f8181526020818152604080832085845282528083206001600160a01b03891680855290835292819020805460ff191688151590811790915581518681529283015293945090927ffeeb3502e62327bd3fece59983b972dc941e6abedd652971aac3adea23cf7e17910160405180910390a3505050565b5f688000000000ab143c065c156126445763ab143c065f526004601cfd5b610bc482612650612d37565b614671565b5f688000000000ab143c065c156126735763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f6001614023565b6387a211a2600c9081525f828152602090912054610bc490610c5a565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a08101919091526126e3613a32565b610bc482610f0a565b688000000000ab143c065c156127095763ab143c065f526004601cfd5b30688000000000ab143c065d61271d613f5d565b612725613a32565b600654816001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612764573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278891906158e2565b146127a657604051631961405760e31b815260040160405180910390fd5b61117481614697565b5f6127b8610bca565b805190602001209050844211156127d657631a15a3cc5f526004601cfd5b6040518860601b60601c98508760601b60601c975065383775081901600e52885f526020600c2080547f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528360208401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604084015246606084015230608084015260a08320602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60208401528960408401528860608401528060808401528760a084015260c08320604e526042602c205f528660ff16602052856040528460605260208060805f60015afa8b3d51146128de5763ddafbaef5f526004601cfd5b0190556303faf4f960a51b88176040526034602c2087905587897f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602060608501a360405250505f606052505050505050565b6387a211a2600c9081525f828152602090912054610bc4565b60405163e6248d5560e01b81526001600160a01b0382811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063e6248d5590602401602060405180830381865afa1580156129b2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc491906158e2565b60607f000000000000000000000000000000000000000000000000000000000000000082806001600160401b03811115612a1257612a126152ed565b604051908082528060200260200182016040528015612a4557816020015b6060815260200190600190039081612a305790505b5060408051606080820183525f80835260208301819052928201529194505b82811015612c2e57868682818110612a7e57612a7e615935565b9050602002810190612a909190615a55565b612a9990615a73565b9150816020015115612bd057815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa158015612aed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b119190615846565b90506001600160a01b038116612b3a57604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d792612b6f9233929190600401615adb565b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050612bad835f01518460400151614795565b868381518110612bbf57612bbf615935565b602002602001018190525050612c26565b81516001600160a01b03163014612bfa57604051637720ccd960e01b815260040160405180910390fd5b612c0830836040015161480a565b858281518110612c1a57612c1a615935565b60200260200101819052505b600101612a64565b5050505092915050565b5f610bc482612650612d37565b600480546040516370a0823160e01b815230928101929092525f9182907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612cb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906158e2565b600954612ceb91906001600160f01b03166158cf565b9050818111612d0d5760405163c0883a5560e01b815260040160405180910390fd5b612d178282615949565b9250505090565b5f612d27613a32565b610b74670de0b6b3a7640000610c845b5f612d4061485e565b600454610b7491906158cf565b5f5f612d606805345cdf77eb68f44c5490565b90508015612d7857612d73848483614898565b610dc7565b509192915050565b5f5f612d936805345cdf77eb68f44c5490565b90508015612d7857612d73848285614934565b306001600160a01b03841603612dc357612dc3638b5fe5a3613433565b612dcb613a32565b612ded6040518060600160405280606081526020015f81526020015f81525090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663da11ee23898989896040518060e001604052808b6001600160a01b03168152602001306001600160a01b031681526020018a815260200189151581526020015f81526020015f81526020015f8152506040518663ffffffff1660e01b8152600401612e87959493929190615b7e565b5f604051808303815f875af1158015612ea2573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ec99190810190615c73565b98509050612efd7f000000000000000000000000000000000000000000000000000000000000000088308460200151613ea8565b60075460b01c5f8080805b87811015612ff1578c8181518110612f2257612f22615935565b60200260200101519350835f0315612fe9578a8a82818110612f4657612f46615935565b9050602002016020810190612f5b9190615090565b915083612f6783610d80565b612f719190615949565b6001600160a01b0383165f908152600a6020526040902060b087901b82179055925060408051858152602081018590526001600160a01b03808f169282019290925290831660608201527f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9060800160405180910390a15b600101612f08565b5084604001518560200181815161300891906158cf565b90525060208501516009546001600160f01b0316101561303757600980546001600160f01b0319169055613073565b602085015160095461305291906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408501511561310c5760045460408601516130939062012fd1906158cf565b8110156130b35760405163ab2169c760e01b815260040160405180910390fd5b60408601516130c29082615949565b60045560408681015181519081526001600160a01b038e1660208201527f92fa6dfbfde0da658c7f8f7d12d2019a8b1972ebf52e449498652ade0455ba2c910160405180910390a1505b8451604051635722baf360e01b81526001600160a01b038a1691635722baf39161313f91908f908f908f90600401615d1d565b5f604051808303815f87803b158015613156575f5ffd5b505af1158015613168573d5f5f3e3d5ffd5b50505050505050505050505050505050565b5f610dc7848484614960565b6040516355eaece960e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063abd5d9d2906024015b602060405180830381865afa1580156131e9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320d9190615861565b61321e5761321e63471656c5613433565b565b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f51141716613257576390b8ec185f526004601cfd5b5f603452505050565b613268613a32565b61327183613e93565b816001600160a01b0316816001600160a01b0316036132a25760405162640b4560e41b815260040160405180910390fd5b6001600160a01b038082165f90815260056020526040812054917f00000000000000000000000000000000000000000000000000000000000000001663b7b7f260308786613301816387a211a2600c9081525f91909152602090205490565b875f891161330f575f613312565b60015b6040518763ffffffff1660e01b815260040161333396959493929190615d51565b6020604051808303815f875af115801561334f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061337391906158e2565b90508015613385576133858184613616565b5050505050565b5f8360601b33602052637f5e9f208117600c526034600c20805460018101156133ca57808511156133c4576313be252b5f526004601cfd5b84810382555b50506387a211a28117600c526020600c208054808511156133f25763f4d678b85f526004601cfd5b84810382555050835f526020600c208381540181555082602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a3505060019392505050565b805f526004601cfd5b5f613445613a32565b61345c61345484612650612d37565b915081613e93565b6040516330ae91d160e21b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c2ba4744906024015f604051808303815f87803b1580156134ba575f5ffd5b505af11580156134cc573d5f5f3e3d5ffd5b50505050610bc48382338561498c565b6001600160a01b0381165f908152600a60205260409020546001600160b01b03161561351b576040516311dd629d60e21b815260040160405180910390fd5b6135258282614a26565b5050565b61353282613e93565b6001600160a01b0381165f908152600560205260409020548281101561355f5761355f63e6c95926613433565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632076d8e73085856135ac876387a211a2600c9081525f91909152602090205490565b8660016040518763ffffffff1660e01b81526004016135d096959493929190615d51565b6020604051808303815f875af11580156135ec573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361091906158e2565b50505050565b6001600160a01b0381165f90815260056020526040902054613639908390615949565b6001600160a01b0382165f9081526005602052604090205560015461365f908390615949565b600155604080518381525f60208201526001600160a01b038316918101919091527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda6906060015b60405180910390a15050565b5f6136bb613a32565b5f6136c583610d80565b905084156136d357846136d5565b805b94506136e085613e93565b808511156136f5576136f5638b5fe5a3613433565b6137217f0000000000000000000000000000000000000000000000000000000000000000853088613ea8565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016634b0319523061375b8885615949565b9350837f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526024810193909352908316604483015260ff166064820152908616608482015260a4015f604051808303815f87803b1580156137fe575f5ffd5b505af1158015613810573d5f5f3e3d5ffd5b50506007546001600160a01b0386165f908152600a602052604090206001600160b01b031990911684179055506138449050565b6009546001600160f01b031685111561386c57600980546001600160f01b03191690556138a4565b6009546138839086906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408051868152602081018390526001600160a01b03868116828401528516606082015290517f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9181900360800190a150929392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529290917f00000000000000000000000000000000000000000000000000000000000000009091169063e6248d5590602401602060405180830381865afa158015613976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399a91906158e2565b815260208082019290925260409081015f9081206001600160a01b038516825290925290205460ff16613525576040516367ee2b0160e11b815260040160405180910390fd5b6139e982613e93565b6387a211a2600c9081525f82905260209020546001600160a01b0382165f90815260056020526040902054613a1f9084906158cf565b11156135255761352563e6c95926613433565b60075464ffffffffff608882901c1642819003613a4d575050565b6009546004546001600160601b0384169164ffffffffff606086901c169160b086901c916001600160f01b0316905f613a888684878a614b3a565b9050844210613bb95760085494965086945f906001600160a01b031663589dc77b613ab161202c565b613abb85886158cf565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160408051808303815f875af1158015613afa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1e9190615d8a565b9097509050808080613b308942615949565b613b3a9190615dac565b613b449190615dcb565b613b4e91906158cf565b9050613b5a81876158cf565b60408051898152602081018390529197507f6ca03c3e1f9f2693eb4277ee4f449b9838fad99c363f5d54bacaf5f71a34afec910160405180910390a1613bab87613ba484876158cf565b888b614b3a565b613bb590836158cf565b9150505b6009545f90613bd7908390600160f01b900461ffff1661271061317a565b90508015613ca1575f613c0f82613bf56805345cdf77eb68f44c5490565b84613c0087896158cf565b613c0a9190615949565b614934565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c6e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c929190615846565b9050613c9e8183614b94565b50505b8115613d305784613cb383878761317a565b613cbd91906158cf565b9450613cc982856158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613cf382846158cf565b60045560408051838152602081018390527f4e32a70f9f06da2cec9f0079d5658935775123a5ce8d0d68de35d019a8d1c19c910160405180910390a15b5050505060609190911b4260881b1760b09190911b176001600160601b0391909116176007555050565b613d6383613e93565b613d6c83614bfd565b6001600160a01b0381165f9081526005602052604090205415613da257604051635d00c4f360e11b815260040160405180910390fd5b5f83613dad83610d80565b613db791906158cf565b6007546001600160a01b0384165f908152600a602052604090206001600160b01b0319909116821790559050600954613dfa9085906001600160f01b03166158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613e457f00000000000000000000000000000000000000000000000000000000000000008486613220565b60408051858152602081018390526001600160a01b0384168183015290517fbec1750eb40c00e8dc2e1c84babbddd5779eaa06c951ab2c66416d05910e7a739181900360600190a150505050565b80613ea55763c0883a555f526004601cfd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716613eea57637939f4245f526004601cfd5b5f60605260405250505050565b8260601b6387a211a28117600c526020600c20805480841115613f215763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a350505050565b60405163de0c7a7160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063de0c7a71906024016131ce565b611770811115613fc057613fc0638b5fe5a3613433565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b91016136a6565b5f61402c613a32565b5f614035612d37565b90505f61404f6140458984612d4d565b9350838784614433565b905084156140665761406186336138fd565b614070565b6140708689614c25565b6001600160a01b038681165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916140d79130918e918d9189918d90600401615d51565b6020604051808303815f875af11580156140f3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061411791906158e2565b90508015614129576141298188613616565b614136848a338b8b614478565b50505095945050505050565b5f61414b613a32565b5f614154612d37565b90505f614162878684614433565b905061417a856141728985612d80565b945084614c25565b6001600160a01b038581165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916141e191309189918c9189918d90600401615d51565b6020604051808303815f875af11580156141fd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061422191906158e2565b90508015614233576142338187613616565b6142408885338a8a614478565b505050949350505050565b6008546040805163ea12489f60e01b8152905130926001600160a01b03169163ea12489f9160048083019260209291908290030181865afa158015614292573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142b69190615846565b6001600160a01b0316146142d1576142d163471656c5613433565b6142da81614c40565b60b0670de0b6b3a7640000901b608842901b606042901b6001600160601b036007541617171760078190555050565b5f614312613a32565b61431b83613e93565b6040516330ae91d160e21b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c2ba4744906024015f604051808303815f87803b158015614379575f5ffd5b505af115801561438b573d5f5f3e3d5ffd5b50505050610bc461439e846122cb612d37565b91508184338561498c565b5f6387a211a2600c52335f526020600c208054808411156143d15763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c335f516020615eda5f395f51905f52602080a350600192915050565b5f5f6144206805345cdf77eb68f44c5490565b90508015612d7857612d73848483614934565b5f61443d84613e93565b506387a211a2600c9081525f839052602090205461445b8183612d4d565b84111561446f5761446f63e6c95926613433565b61141a84614bfd565b6144828185614d01565b61448b85614d62565b6144b67f00000000000000000000000000000000000000000000000000000000000000008387613220565b806001600160a01b0316826001600160a01b0316846001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db888860405161450e929190918252602082015260400190565b60405180910390a45050505050565b604051632748468360e11b81523390634e908d0690614546903090899088908790600401615de2565b5f604051808303815f87803b15801561455d575f5ffd5b505af115801561456f573d5f5f3e3d5ffd5b50506387a211a2600c9081525f869052602090205461459192508691506158cf565b82146145b05760405163350385ad60e11b815260040160405180910390fd5b6001600160a01b038381165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916146179130918a918a918a918990600401615d51565b6020604051808303815f875af1158015614633573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465791906158e2565b90508015614669576146698185613616565b505050505050565b5f5f6146846805345cdf77eb68f44c5490565b90508015612d7857612d73848285614898565b6146a881638ec124b360e01b614d76565b6146b9576146b9638b5fe5a3613433565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa158015614718573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061473c91906158e2565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a032906060015b60405180910390a1505050565b60605f5f846001600160a01b03165f856040516147b29190615ec3565b5f6040518083038185875af1925050503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b606091505b5091509150614801858383614d91565b95945050505050565b60605f5f846001600160a01b0316846040516148269190615ec3565b5f60405180830381855af49150503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b6007546009545f9190612076906001600160601b038316906001600160f01b031664ffffffffff606085901c811690608886901c16614b3a565b8282025f1983850981811082019003806148c757826148be5763ae47f7025f526004601cfd5b5081900461141a565b8083116148db5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f614940848484614898565b9050818385091561141a576001018061141a5763ae47f7025f526004601cfd5b5f825f19048411830215820261497d5763ad251c275f526004601cfd5b50910281810615159190040190565b6149b87f0000000000000000000000000000000000000000000000000000000000000000833087613ea8565b6149c184614dd9565b6149cb8184614b94565b806001600160a01b0316826001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78686604051614a19929190918252602082015260400190565b60405180910390a3613610565b5f82600154614a3591906158cf565b6040516301ac71bb60e11b81523060048201526001600160a01b038481166024830152604482018390529192507f000000000000000000000000000000000000000000000000000000000000000090911690630358e376906064015f604051808303815f87803b158015614aa7575f5ffd5b505af1158015614ab9573d5f5f3e3d5ffd5b5050506001600160a01b0383165f90815260056020526040902054614ae0915084906158cf565b6001600160a01b0383165f818152600560209081526040918290209390935560018481558151878152938401528201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda690606001614788565b5f5f85118015614b4957508282105b15610dc757614801834210614b7157614b628385615949565b614b6c9087615dcb565b614b85565b614b7b8342615949565b614b859087615dcb565b85670de0b6b3a7640000614de7565b6805345cdf77eb68f44c5481810181811015614bb75763e5cfe9575f526004601cfd5b806805345cdf77eb68f44c5550506387a211a2600c52815f526020600c208181540181555080602052600c5160601c5f5f516020615eda5f395f51905f52602080a35050565b80614c0661202c565b1015613ea55760405163ab2169c760e01b815260040160405180910390fd5b336001600160a01b0383161461352557613525823383614df3565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614614c7d57614c7d63471656c5613433565b3062012fd1614cae7f0000000000000000000000000000000000000000000000000000000000000000848484613ea8565b80614cb95f82614b94565b600482905560408051838152602081018390525f916001600160a01b038716917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101614a19565b6387a211a2600c52815f526020600c20805480831115614d285763f4d678b85f526004601cfd5b82900390556805345cdf77eb68f44c805482900390555f8181526001600160a01b0383165f516020615eda5f395f51905f52602083a35050565b80600454614d709190615949565b60045550565b5f614d8083614e31565b801561141a575061141a8383614e63565b6060614d9d8383614ee9565b8151158015614db457506001600160a01b0384163b155b15614dd2576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b80600454614d7091906158cf565b5f610dc7848484614f17565b81602052637f5e9f20600c52825f526034600c20805460018101156133855780831115614e27576313be252b5f526004601cfd5b9190910390555050565b5f614e43826301ffc9a760e01b614e63565b8015610bc45750614e5c826001600160e01b0319614e63565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015614ed3575060208210155b8015614ede57505f81115b979650505050505050565b816135255780515f03614f0f576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f825f190484118302158202614f345763ad251c275f526004601cfd5b5091020490565b5f60208284031215614f4b575f5ffd5b81356001600160e01b03198116811461141a575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61141a6020830184614f62565b5f60208284031215614fb2575f5ffd5b5035919050565b6001600160a01b0381168114613ea5575f5ffd5b5f5f60408385031215614fde575f5ffd5b8235614fe981614fb9565b946020939093013593505050565b5f5f83601f840112615007575f5ffd5b5081356001600160401b0381111561501d575f5ffd5b6020830191508360208260051b8501011115615037575f5ffd5b9250929050565b5f5f5f60408486031215615050575f5ffd5b83356001600160401b03811115615065575f5ffd5b61507186828701614ff7565b909450925050602084013561508581614fb9565b809150509250925092565b5f602082840312156150a0575f5ffd5b813561141a81614fb9565b5f5f5f606084860312156150bd575f5ffd5b83356150c881614fb9565b925060208401356150d881614fb9565b929592945050506040919091013590565b5f5f604083850312156150fa575f5ffd5b82359150602083013561510c81614fb9565b809150509250929050565b5f5f5f5f5f6060868803121561512b575f5ffd5b85356001600160401b03811115615140575f5ffd5b61514c88828901614ff7565b90965094505060208601356001600160401b0381111561516a575f5ffd5b61517688828901614ff7565b909450925050604086013561518a81614fb9565b809150509295509295909350565b5f5f5f604084860312156151aa575f5ffd5b8335925060208401356001600160401b038111156151c6575f5ffd5b8401601f810186136151d6575f5ffd5b80356001600160401b038111156151eb575f5ffd5b8660208284010111156151fc575f5ffd5b939660209190910195509293505050565b5f5f5f5f5f60608688031215615221575f5ffd5b85356001600160401b03811115615236575f5ffd5b61524288828901614ff7565b909650945050602086013561525681614fb9565b925060408601356001600160401b03811115615270575f5ffd5b61527c88828901614ff7565b969995985093965092949392505050565b5f5f5f6060848603121561529f575f5ffd5b8335925060208401356152b181614fb9565b9150604084013561508581614fb9565b5f5f604083850312156152d2575f5ffd5b82356152dd81614fb9565b9150602083013561510c81614fb9565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b0381118282101715615323576153236152ed565b60405290565b604051606081016001600160401b0381118282101715615323576153236152ed565b604051601f8201601f191681016001600160401b0381118282101715615373576153736152ed565b604052919050565b8035610c8981614fb9565b5f82601f830112615395575f5ffd5b81356001600160401b038111156153ae576153ae6152ed565b6153c1601f8201601f191660200161534b565b8181528460208386010111156153d5575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c08284031215615401575f5ffd5b615409615301565b9050813561541681614fb9565b815260208281013590820152604082013561543081614fb9565b6040820152606082013561544381614fb9565b60608201526080828101359082015260a08201356001600160401b0381111561546a575f5ffd5b61547684828501615386565b60a08301525092915050565b5f5f5f60608486031215615494575f5ffd5b8335925060208401356154a681614fb9565b915060408401356001600160401b038111156154c0575f5ffd5b840160c081870312156154d1575f5ffd5b6154d9615301565b6154e28261537b565b8152602082810135908201526154fa6040830161537b565b60408201526060828101359082015260808201356001600160401b03811115615521575f5ffd5b61552d888285016153f1565b60808301525060a08201356001600160401b0381111561554b575f5ffd5b61555788828501615386565b60a08301525080925050509250925092565b5f6001600160401b03821115615581576155816152ed565b5060051b60200190565b5f82601f83011261559a575f5ffd5b81356155ad6155a882615569565b61534b565b8082825260208201915060208360051b8601019250858311156155ce575f5ffd5b602085015b8381101561560e5780356001600160401b038111156155f0575f5ffd5b6155ff886020838a01016153f1565b845250602092830192016155d3565b5095945050505050565b5f5f5f6060848603121561562a575f5ffd5b83359250602084013561563c81614fb9565b915060408401356001600160401b03811115615656575f5ffd5b840160c08187031215615667575f5ffd5b61566f615301565b6156788261537b565b8152602082810135908201526156906040830161537b565b60408201526060828101359082015260808201356001600160401b038111156156b7575f5ffd5b61552d8882850161558b565b8015158114613ea5575f5ffd5b5f5f604083850312156156e1575f5ffd5b82356156ec81614fb9565b9150602083013561510c816156c3565b5f5f5f5f5f5f5f60e0888a031215615712575f5ffd5b873561571d81614fb9565b9650602088013561572d81614fb9565b95506040880135945060608801359350608088013560ff81168114615750575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f6020838503121561577e575f5ffd5b82356001600160401b03811115615793575f5ffd5b61579f85828601614ff7565b90969095509350505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561580257603f198786030184526157ed858351614f62565b945060209384019391909101906001016157d1565b50929695505050505050565b600181811c9082168061582257607f821691505b60208210810361584057634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215615856575f5ffd5b815161141a81614fb9565b5f60208284031215615871575f5ffd5b815161141a816156c3565b634e487b7160e01b5f52601160045260245ffd5b5f5f5f606084860312156158a2575f5ffd5b83516158ad816156c3565b60208501519093506158be816156c3565b6040850151909250615085816156c3565b80820180821115610bc457610bc461587c565b5f602082840312156158f2575f5ffd5b5051919050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610bc457610bc461587c565b80516001600160a01b03908116835260208083015190840152604080830151821690840152606080830151909116908301526080808201519083015260a08181015160c09184018290525f91610dc790850182614f62565b60018060a01b038516815283602082015260018060a01b03831660408201526080606082015260018060a01b038251166080820152602082015160a082015260018060a01b0360408301511660c0820152606082015160e08201525f608083015160c0610100840152615a2b61014084018261595c565b905060a0840151607f1984830301610120850152615a498282614f62565b98975050505050505050565b5f8235605e19833603018112615a69575f5ffd5b9190910192915050565b5f60608236031215615a83575f5ffd5b615a8b615329565b8235615a9681614fb9565b81526020830135615aa6816156c3565b602082015260408301356001600160401b03811115615ac3575f5ffd5b615acf36828601615386565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061480190830184614f62565b5f8151808452602084019350602083015f5b82811015615b36578151865260209586019590910190600101615b18565b5093949350505050565b8183526020830192505f815f5b84811015615b36578135615b6081614fb9565b6001600160a01b031686526020958601959190910190600101615b4d565b61014081525f615b92610140830188615b06565b6001600160a01b03871660208401528281036040840152615bb4818688615b40565b91505060018060a01b03835116606083015260018060a01b036020840151166080830152604083015160a08301526060830151151560c0830152608083015160e083015260a083015161010083015260c08301516101208301529695505050505050565b5f82601f830112615c27575f5ffd5b8151615c356155a882615569565b8082825260208201915060208360051b860101925085831115615c56575f5ffd5b602085015b8381101561560e578051835260209283019201615c5b565b5f5f60408385031215615c84575f5ffd5b82516001600160401b03811115615c99575f5ffd5b830160608186031215615caa575f5ffd5b615cb2615329565b81516001600160401b03811115615cc7575f5ffd5b615cd387828501615c18565b8252506020828101518183015260409283015192820192909252908401519092506001600160401b03811115615d07575f5ffd5b615d1385828601615c18565b9150509250929050565b606081525f615d2f6060830187615b06565b6001600160a01b03861660208401528281036040840152614ede818587615b40565b6001600160a01b03968716815260208101959095529290941660408401526060830152608082019290925290151560a082015260c00190565b5f5f60408385031215615d9b575f5ffd5b505080516020909101519092909150565b5f82615dc657634e487b7160e01b5f52601260045260245ffd5b500490565b8082028115828204841417610bc457610bc461587c565b60018060a01b038516815283602082015260018060a01b0383166040820152608060608201525f610140820160018060a01b038451166080840152602084015160a084015260018060a01b0360408501511660c0840152606084015160e0840152608084015160c0610100850152818151808452610160860191506101608160051b87010193506020830192505f5b81811015615ea35761015f19878603018352615e8e85855161595c565b94506020938401939290920191600101615e71565b5050505060a0840151838203607f1901610120850152615a498282614f62565b5f82518060208501845e5f92019182525091905056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122074fb7caf678ec10c7ddfffe1fc72b7e28011c552aa37a2b16c4ca7bf2a51e55864736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b9000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b0000000000000000000000000db363a2edb3ac8f4cddc174ff44b6dfd09a2fef
Deployed Bytecode
0x608060405234801561000f575f5ffd5b506004361061047a575f3560e01c806372d46ac211610258578063b3d7f6b91161014b578063d4bb0c73116100ca578063e28d591d1161008f578063e28d591d14610ad9578063e6248d5514610af8578063e8bbf5d714610b0b578063ef8b30f714610b2b578063f0c00c4114610b3e578063f411029114610b46575f5ffd5b8063d4bb0c7314610a6f578063d505accf14610a82578063d905777e14610a95578063dd62ed3e14610aa8578063deee770414610ad0575f5ffd5b8063c63d75b611610110578063c63d75b6146106b0578063c6e6f59214610a23578063cd88c07214610a36578063ce96cb7714610a49578063cf6af22d14610a5c575f5ffd5b8063b3d7f6b9146109c4578063b460af94146109d7578063ba087652146109ea578063bdca6723146109fd578063c3c854b614610a10575f5ffd5b806394bf804d116101d7578063a7af467a1161019c578063a7af467a14610970578063a9059cbb14610983578063ab21e62814610996578063ad9d3683146109a9578063b3bffb45146109b1575f5ffd5b806394bf804d1461090757806395d89b411461091a5780639616756e146109225780639e591a4414610935578063a75df49814610948575f5ffd5b80637ecebe001161021d5780637ecebe001461089757806380fd997f146108bc57806385b13080146108c557806387367d71146108d85780638f73dcfa146108e0575f5ffd5b806372d46ac2146108385780637313ee5a1461084b578063775a814a146108545780637ada7a091461085c5780637c0e0c8c1461086f575f5ffd5b806338d52e0f116103705780635722baf3116102ef578063635d9771116102b4578063635d9771146107af578063640fef7b146107da5780636779db5b146107ed5780636e553f651461080057806370a0823114610813575f5ffd5b80635722baf31461075057806357d159d5146107635780635b56d6f5146107765780635c0bfa88146107895780635fec5d0b1461079c575f5ffd5b806345d7b97a1161033557806345d7b97a146106fd5780634b3fd148146107045780634cdad5061461071757806350f2012f1461072a5780635296a4311461073d575f5ffd5b806338d52e0f146106825780633ba0b9a9146106a8578063402d267d146106b057806340c09eba146106c357806341ed2c12146106d6575f5ffd5b80631dd19cb4116103fc578063313ce567116103c1578063313ce567146106105780633237c158146106415780633644e51514610654578063371fd8e61461065c57806338c0f3091461066f575f5ffd5b80631dd19cb41461054a5780631e75db1614610552578063215702561461057d57806323b872dd146105ea5780632f4a61d9146105fd575f5ffd5b80630a28a477116104425780630a28a477146104f75780630f0f54361461050a57806311005b071461051f578063176679671461053257806318160ddd1461053a575f5ffd5b806301e1d1141461047e57806301ffc9a71461049957806306fdde03146104bc57806307a2d13a146104d1578063095ea7b3146104e4575b5f5ffd5b610486610b4e565b6040519081526020015b60405180910390f35b6104ac6104a7366004614f3b565b610b79565b6040519015158152602001610490565b6104c4610bca565b6040516104909190614f90565b6104866104df366004614fa2565b610c5a565b6104ac6104f2366004614fcd565b610c8e565b610486610505366004614fa2565b610cdd565b61051d61051836600461503e565b610cef565b005b61048661052d366004615090565b610d80565b610486600481565b6805345cdf77eb68f44c54610486565b61051d610dcf565b600854610565906001600160a01b031681565b6040516001600160a01b039091168152602001610490565b61059061058b366004615090565b610f0a565b604051610490919081516001600160a01b0390811682526020808401519091169082015260408083015160ff16908201526060808301511515908201526080808301519082015260a0918201519181019190915260c00190565b6104ac6105f83660046150ab565b610fdf565b61048661060b3660046150e9565b611037565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152602001610490565b61051d61064f366004614fa2565b611137565b610486611183565b61051d61066a366004614fa2565b6111ff565b61051d61067d366004615117565b611243565b7f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b9610565565b6104866112d9565b6104866106be366004615090565b6112ee565b61051d6106d13660046150e9565b611421565b6105657f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b81565b60016104ac565b61051d6107123660046150e9565b611478565b610486610725366004614fa2565b61156d565b61051d610738366004614fa2565b61157a565b61051d61074b366004615198565b6115b7565b61051d61075e36600461520d565b611781565b610486610771366004615090565b611994565b61051d610784366004614fa2565b6119e2565b61048661079736600461528d565b611a24565b6104ac6107aa3660046152c1565b611a71565b6009546107c2906001600160f01b031681565b6040516001600160f01b039091168152602001610490565b61051d6107e836600461528d565b611b41565b6104866107fb36600461528d565b611c51565b61048661080e3660046150e9565b611c89565b610486610821366004615090565b6387a211a2600c9081525f91909152602090205490565b61048661084636600461528d565b611cd1565b61048660065481565b61051d611d08565b6104ac61086a366004615090565b611d47565b610877611d8e565b604080519485526020850193909352918301526060820152608001610490565b6104866108a5366004615090565b6338377508600c9081525f91909152602090205490565b61048661177081565b61051d6108d3366004615482565b611ddf565b61048661202c565b6105657f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b6104866109153660046150e9565b61207c565b6104c46120b0565b6104ac610930366004615090565b6120bf565b61051d6109433660046150e9565b61214b565b60095461095d90600160f01b900461ffff1681565b60405161ffff9091168152602001610490565b61048661097e366004614fa2565b612190565b6104ac610991366004614fcd565b61219f565b61051d6109a43660046150e9565b6121f5565b61048661223c565b6104866109bf3660046150e9565b61228a565b6104866109d2366004614fa2565b6122be565b6104866109e536600461528d565b6122d0565b6104866109f836600461528d565b612306565b61051d610a0b366004615618565b61233d565b61051d610a1e3660046156d0565b612459565b610486610a31366004614fa2565b612626565b610486610a4436600461528d565b612655565b610486610a57366004615090565b61268d565b610590610a6a366004615090565b6126aa565b61051d610a7d366004615090565b6126ec565b61051d610a903660046156fc565b6127af565b610486610aa3366004615090565b612931565b610486610ab63660046152c1565b602052637f5e9f20600c9081525f91909152603490205490565b61048660015481565b610486610ae7366004615090565b60056020525f908152604090205481565b610486610b06366004615090565b61294a565b610b1e610b1936600461576d565b6129d6565b60405161049091906157ab565b610486610b39366004614fa2565b612c38565b610486612c45565b610486612d1e565b5f688000000000ab143c065c15610b6c5763ab143c065f526004601cfd5b610b74612d37565b905090565b5f6001600160e01b03198216630934615b60e01b1480610ba957506001600160e01b0319821663b6e300c760e01b145b80610bc457506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610bd99061580e565b80601f0160208091040260200160405190810160405280929190818152602001828054610c059061580e565b8015610c505780601f10610c2757610100808354040283529160200191610c50565b820191905f5260205f20905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b5f688000000000ab143c065c15610c785763ab143c065f526004601cfd5b610bc482610c84612d37565b612d4d565b919050565b5f82602052637f5e9f20600c52335f52816034600c2055815f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa350600192915050565b5f610bc482610cea612d37565b612d80565b688000000000ab143c065c15610d0c5763ab143c065f526004601cfd5b30688000000000ab143c065d815f816001600160401b03811115610d3257610d326152ed565b604051908082528060200260200182016040528015610d5b578160200160208202803683370190505b509050610d6d8133878787875f612da6565b50505f688000000000ab143c065d505050565b6001600160a01b0381165f908152600a60205260408120546001600160b01b038116808303610db0575050919050565b600754610dc790829060b090811c9085901c61317a565b949350505050565b688000000000ab143c065c15610dec5763ab143c065f526004601cfd5b30688000000000ab143c065d610e00613186565b5f610e09612c45565b90505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e68573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8c9190615846565b9050610eb97f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b98284613220565b604080518381526001600160a01b03831660208201527f88fc2578c4b534418a67792f942c22deab48988e8f00bf87d4f8b0d0a8655772910160405180910390a150505f688000000000ab143c065d565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610f4483610d80565b3083526001600160a01b037f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b916602084015290507f000000000000000000000000000000000000000000000000000000000000001260ff16604083015280610fad576001610faf565b5f5b151560608301526001600160a01b039092165f90815260056020526040902054608082015260a081019190915290565b5f688000000000ab143c065c15610ffd5763ab143c065f526004601cfd5b30688000000000ab143c065d611014828486613260565b61101f84848461338c565b50600190505f688000000000ab143c065d9392505050565b5f688000000000ab143c065c156110555763ab143c065f526004601cfd5b30688000000000ab143c065d336001600160a01b038316148015906110fd5750604051630a73e39160e01b81523360048201527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b031690630a73e39190602401602060405180830381865afa1580156110d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fb9190615861565b155b1561110f5761110f63471656c5613433565b611119838361343c565b905061112581836134dc565b5f688000000000ab143c065d92915050565b688000000000ab143c065c156111545763ab143c065f526004601cfd5b30688000000000ab143c065d61116a8133613529565b6111748133613616565b5f688000000000ab143c065d50565b5f8061118d610bca565b8051906020012090506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81528160208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015260a081209250505090565b688000000000ab143c065c1561121c5763ab143c065f526004601cfd5b30688000000000ab143c065d6112338133336136b2565b505f688000000000ab143c065d50565b688000000000ab143c065c156112605763ab143c065f526004601cfd5b30688000000000ab143c065d8184811461128157611281638b5fe5a3613433565b6112c58686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525033925088915087905086866001612da6565b505f688000000000ab143c065d5050505050565b5f610b74670de0b6b3a7640000610c84612d37565b60405163699ba8b360e01b81523060048201525f9081906001600160a01b037f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b169063699ba8b390602401606060405180830381865afa158015611354573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113789190615890565b5050604051637bca031760e11b81523060048201529091507f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b03169063f794062e90602401602060405180830381865afa1580156113df573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114039190615861565b158061140c5750805b156114175750919050565b5f195b9392505050565b688000000000ab143c065c1561143e5763ab143c065f526004601cfd5b30688000000000ab143c065d61145481336138fd565b61145e82826139e0565b61146882826134dc565b5f688000000000ab143c065d5050565b688000000000ab143c065c156114955763ab143c065f526004601cfd5b30688000000000ab143c065d6114a9613a32565b6009546001600160a01b037f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b169063f96492c9903090859033906114f79083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b15801561154c575f5ffd5b505af115801561155e573d5f5f3e3d5ffd5b50505050611468828233613d5a565b5f610bc482610c84612d37565b688000000000ab143c065c156115975763ab143c065f526004601cfd5b30688000000000ab143c065d6115ad81336139e0565b61117481336134dc565b6115bf613a32565b6115c883613e93565b6040516370a0823160e01b81523060048201527f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b96001600160a01b0316906370a0823190602401602060405180830381865afa15801561162a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164e91906158e2565b83111561166e5760405163ab2169c760e01b815260040160405180910390fd5b7f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b95f61169985612190565b90505f6116a682876158cf565b90506116b3833388613220565b604051637924fd7d60e01b81523390637924fd7d906116dc90899085908a908a906004016158f9565b6020604051808303815f875af11580156116f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061171c91906158e2565b5061172983333084613ea8565b8160045461173791906158cf565b6004556040805187815260208101849052338183015290517fb216ab52d7988a2a0e79070667f92d2ade5e6464ee97984d5983afe3572348269181900360600190a1505050505050565b688000000000ab143c065c1561179e5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630eaa39a960e31b81523060048201523360248201527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b031690637551cd48906044015f604051808303815f87803b15801561180e575f5ffd5b505af1158015611820573d5f5f3e3d5ffd5b508392505f915081905080805b848110156119695789898281811061184757611847615935565b905060200201359250825f03156119615786868281811061186a5761186a615935565b905060200201602081019061187f9190615090565b915061188b83856158cf565b6001600160a01b0383165f908152600560205260409020549094506118b1908490615949565b6001600160a01b0383165f81815260056020908152604080832094909455835187815290810191909152918201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda69060600160405180910390a1611917828985613ef7565b604080518481526001600160a01b038a8116602083015284168183015290517f6ee556dbce23a24ad3b539ee42191a2dd262b16ecb4d0ef20dbeb4bb5a9a23839181900360600190a15b60010161182d565b50826001546119789190615949565b600155505f9250688000000000ab143c069150505d5050505050565b5f688000000000ab143c065c156119b25763ab143c065f526004601cfd5b30688000000000ab143c065d6119c6613a32565b6119cf82610d80565b90505f688000000000ab143c065d919050565b688000000000ab143c065c156119ff5763ab143c065f526004601cfd5b30688000000000ab143c065d611a13613f5d565b611a1b613a32565b61117481613fa9565b5f688000000000ab143c065c15611a425763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c84848460015f614023565b90505f688000000000ab143c065d9392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529092909183917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff169063e6248d5590602401602060405180830381865afa158015611aeb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0f91906158e2565b815260208082019290925260409081015f9081206001600160a01b039095168152939091529091205460ff1692915050565b688000000000ab143c065c15611b5e5763ab143c065f526004601cfd5b30688000000000ab143c065d611b7481336138fd565b611b7c613a32565b6009546001600160a01b037f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b169063f96492c990309086908590611bca9083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b158015611c1f575f5ffd5b505af1158015611c31573d5f5f3e3d5ffd5b50505050611c40838383613d5a565b5f688000000000ab143c065d505050565b5f688000000000ab143c065c15611c6f5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c848484600180614023565b5f688000000000ab143c065c15611ca75763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd838361343c565b90505f688000000000ab143c065d92915050565b5f688000000000ab143c065c15611cef5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484846001614142565b688000000000ab143c065c15611d255763ab143c065f526004601cfd5b30688000000000ab143c065d611d39613a32565b5f688000000000ab143c065d565b5f688000000000ab143c065c15611d655763ab143c065f526004601cfd5b30688000000000ab143c065d611d7a8261424b565b5060015f688000000000ab143c065d919050565b5f5f5f5f688000000000ab143c065c15611daf5763ab143c065f526004601cfd5b50506007546001600160601b0381169364ffffffffff606083901c81169450608883901c16925060b09190911c90565b688000000000ab143c065c15611dfc5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b031690630a73e39190602401602060405180830381865afa158015611e6a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8e9190615861565b611e9f57611e9f63471656c5613433565b611ea7613a32565b60405163463aea7f60e11b81523060048201526001600160a01b0383811660248301527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b1690638c75d4fe906044015f604051808303815f87803b158015611f0d575f5ffd5b505af1158015611f1f573d5f5f3e3d5ffd5b50505050611f2e833384613d5a565b6040516318f9a83960e21b815233906363e6a0e490611f579030908790879087906004016159b4565b5f604051808303815f87803b158015611f6e575f5ffd5b505af1158015611f80573d5f5f3e3d5ffd5b5050600954604051630967a76b60e31b81523060048201525f60248201526001600160a01b0386811660448301526001600160f01b0390921660648201527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b9091169250634b3d3b5891506084015f604051808303815f87803b158015612005575f5ffd5b505af1158015612017573d5f5f3e3d5ffd5b505050505f688000000000ab143c065d505050565b6004545f90808203612051576040516354e9f59b60e01b815260040160405180910390fd5b60095462012fd19061206c906001600160f01b031683615949565b6120769190615949565b91505090565b5f688000000000ab143c065c1561209a5763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd8383614309565b606060038054610bd99061580e565b604051634b0b3ab760e11b81526001600160a01b0382811660048301525f917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff90911690639616756e90602401602060405180830381865afa158015612127573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc49190615861565b688000000000ab143c065c156121685763ab143c065f526004601cfd5b30688000000000ab143c065d61217f8233836136b2565b505f688000000000ab143c065d5050565b5f610bc482600461271061317a565b5f688000000000ab143c065c156121bd5763ab143c065f526004601cfd5b30688000000000ab143c065d6121d4828433613260565b6121de83836143a9565b50600190505f688000000000ab143c065d92915050565b688000000000ab143c065c156122125763ab143c065f526004601cfd5b30688000000000ab143c065d61222881336138fd565b6122328282613529565b6114688282613616565b5f688000000000ab143c065c1561225a5763ab143c065f526004601cfd5b30688000000000ab143c065d61226e613a32565b506009546001600160f01b03165f688000000000ab143c065d90565b5f688000000000ab143c065c156122a85763ab143c065f526004601cfd5b30688000000000ab143c065d61110f82336138fd565b5f610bc4826122cb612d37565b61440d565b5f688000000000ab143c065c156122ee5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f614142565b5f688000000000ab143c065c156123245763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f5f614023565b688000000000ab143c065c1561235a5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b031690630a73e39190602401602060405180830381865afa1580156123c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ec9190615861565b6123fd576123fd63471656c5613433565b612405613a32565b5f61240e612d37565b90505f61241c858584614433565b90505f6124298684612d80565b90506124388682333389614478565b612445868287858861451d565b5050505f688000000000ab143c065d505050565b336001600160a01b0383160361248257604051636eef2f3f60e11b815260040160405180910390fd5b604051634b0b3ab760e11b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031690639616756e90602401602060405180830381865afa1580156124e4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125089190615861565b15612526576040516302d5da9f60e01b815260040160405180910390fd5b60405163e6248d5560e01b81523360048201525f907f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063e6248d5590602401602060405180830381865afa15801561258a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125ae91906158e2565b335f8181526020818152604080832085845282528083206001600160a01b03891680855290835292819020805460ff191688151590811790915581518681529283015293945090927ffeeb3502e62327bd3fece59983b972dc941e6abedd652971aac3adea23cf7e17910160405180910390a3505050565b5f688000000000ab143c065c156126445763ab143c065f526004601cfd5b610bc482612650612d37565b614671565b5f688000000000ab143c065c156126735763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f6001614023565b6387a211a2600c9081525f828152602090912054610bc490610c5a565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a08101919091526126e3613a32565b610bc482610f0a565b688000000000ab143c065c156127095763ab143c065f526004601cfd5b30688000000000ab143c065d61271d613f5d565b612725613a32565b600654816001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612764573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278891906158e2565b146127a657604051631961405760e31b815260040160405180910390fd5b61117481614697565b5f6127b8610bca565b805190602001209050844211156127d657631a15a3cc5f526004601cfd5b6040518860601b60601c98508760601b60601c975065383775081901600e52885f526020600c2080547f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528360208401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604084015246606084015230608084015260a08320602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60208401528960408401528860608401528060808401528760a084015260c08320604e526042602c205f528660ff16602052856040528460605260208060805f60015afa8b3d51146128de5763ddafbaef5f526004601cfd5b0190556303faf4f960a51b88176040526034602c2087905587897f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602060608501a360405250505f606052505050505050565b6387a211a2600c9081525f828152602090912054610bc4565b60405163e6248d5560e01b81526001600160a01b0382811660048301525f917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff9091169063e6248d5590602401602060405180830381865afa1580156129b2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc491906158e2565b60607f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff82806001600160401b03811115612a1257612a126152ed565b604051908082528060200260200182016040528015612a4557816020015b6060815260200190600190039081612a305790505b5060408051606080820183525f80835260208301819052928201529194505b82811015612c2e57868682818110612a7e57612a7e615935565b9050602002810190612a909190615a55565b612a9990615a73565b9150816020015115612bd057815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa158015612aed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b119190615846565b90506001600160a01b038116612b3a57604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d792612b6f9233929190600401615adb565b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050612bad835f01518460400151614795565b868381518110612bbf57612bbf615935565b602002602001018190525050612c26565b81516001600160a01b03163014612bfa57604051637720ccd960e01b815260040160405180910390fd5b612c0830836040015161480a565b858281518110612c1a57612c1a615935565b60200260200101819052505b600101612a64565b5050505092915050565b5f610bc482612650612d37565b600480546040516370a0823160e01b815230928101929092525f9182907f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b96001600160a01b0316906370a0823190602401602060405180830381865afa158015612cb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906158e2565b600954612ceb91906001600160f01b03166158cf565b9050818111612d0d5760405163c0883a5560e01b815260040160405180910390fd5b612d178282615949565b9250505090565b5f612d27613a32565b610b74670de0b6b3a7640000610c845b5f612d4061485e565b600454610b7491906158cf565b5f5f612d606805345cdf77eb68f44c5490565b90508015612d7857612d73848483614898565b610dc7565b509192915050565b5f5f612d936805345cdf77eb68f44c5490565b90508015612d7857612d73848285614934565b306001600160a01b03841603612dc357612dc3638b5fe5a3613433565b612dcb613a32565b612ded6040518060600160405280606081526020015f81526020015f81525090565b7f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b031663da11ee23898989896040518060e001604052808b6001600160a01b03168152602001306001600160a01b031681526020018a815260200189151581526020015f81526020015f81526020015f8152506040518663ffffffff1660e01b8152600401612e87959493929190615b7e565b5f604051808303815f875af1158015612ea2573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ec99190810190615c73565b98509050612efd7f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b988308460200151613ea8565b60075460b01c5f8080805b87811015612ff1578c8181518110612f2257612f22615935565b60200260200101519350835f0315612fe9578a8a82818110612f4657612f46615935565b9050602002016020810190612f5b9190615090565b915083612f6783610d80565b612f719190615949565b6001600160a01b0383165f908152600a6020526040902060b087901b82179055925060408051858152602081018590526001600160a01b03808f169282019290925290831660608201527f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9060800160405180910390a15b600101612f08565b5084604001518560200181815161300891906158cf565b90525060208501516009546001600160f01b0316101561303757600980546001600160f01b0319169055613073565b602085015160095461305291906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408501511561310c5760045460408601516130939062012fd1906158cf565b8110156130b35760405163ab2169c760e01b815260040160405180910390fd5b60408601516130c29082615949565b60045560408681015181519081526001600160a01b038e1660208201527f92fa6dfbfde0da658c7f8f7d12d2019a8b1972ebf52e449498652ade0455ba2c910160405180910390a1505b8451604051635722baf360e01b81526001600160a01b038a1691635722baf39161313f91908f908f908f90600401615d1d565b5f604051808303815f87803b158015613156575f5ffd5b505af1158015613168573d5f5f3e3d5ffd5b50505050505050505050505050505050565b5f610dc7848484614960565b6040516355eaece960e11b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063abd5d9d2906024015b602060405180830381865afa1580156131e9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320d9190615861565b61321e5761321e63471656c5613433565b565b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f51141716613257576390b8ec185f526004601cfd5b5f603452505050565b613268613a32565b61327183613e93565b816001600160a01b0316816001600160a01b0316036132a25760405162640b4560e41b815260040160405180910390fd5b6001600160a01b038082165f90815260056020526040812054917f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b1663b7b7f260308786613301816387a211a2600c9081525f91909152602090205490565b875f891161330f575f613312565b60015b6040518763ffffffff1660e01b815260040161333396959493929190615d51565b6020604051808303815f875af115801561334f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061337391906158e2565b90508015613385576133858184613616565b5050505050565b5f8360601b33602052637f5e9f208117600c526034600c20805460018101156133ca57808511156133c4576313be252b5f526004601cfd5b84810382555b50506387a211a28117600c526020600c208054808511156133f25763f4d678b85f526004601cfd5b84810382555050835f526020600c208381540181555082602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a3505060019392505050565b805f526004601cfd5b5f613445613a32565b61345c61345484612650612d37565b915081613e93565b6040516330ae91d160e21b81523060048201527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b03169063c2ba4744906024015f604051808303815f87803b1580156134ba575f5ffd5b505af11580156134cc573d5f5f3e3d5ffd5b50505050610bc48382338561498c565b6001600160a01b0381165f908152600a60205260409020546001600160b01b03161561351b576040516311dd629d60e21b815260040160405180910390fd5b6135258282614a26565b5050565b61353282613e93565b6001600160a01b0381165f908152600560205260409020548281101561355f5761355f63e6c95926613433565b7f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b0316632076d8e73085856135ac876387a211a2600c9081525f91909152602090205490565b8660016040518763ffffffff1660e01b81526004016135d096959493929190615d51565b6020604051808303815f875af11580156135ec573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361091906158e2565b50505050565b6001600160a01b0381165f90815260056020526040902054613639908390615949565b6001600160a01b0382165f9081526005602052604090205560015461365f908390615949565b600155604080518381525f60208201526001600160a01b038316918101919091527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda6906060015b60405180910390a15050565b5f6136bb613a32565b5f6136c583610d80565b905084156136d357846136d5565b805b94506136e085613e93565b808511156136f5576136f5638b5fe5a3613433565b6137217f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b9853088613ea8565b6001600160a01b037f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b16634b0319523061375b8885615949565b9350837f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b97f00000000000000000000000000000000000000000000000000000000000000126040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526024810193909352908316604483015260ff166064820152908616608482015260a4015f604051808303815f87803b1580156137fe575f5ffd5b505af1158015613810573d5f5f3e3d5ffd5b50506007546001600160a01b0386165f908152600a602052604090206001600160b01b031990911684179055506138449050565b6009546001600160f01b031685111561386c57600980546001600160f01b03191690556138a4565b6009546138839086906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408051868152602081018390526001600160a01b03868116828401528516606082015290517f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9181900360800190a150929392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529290917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff9091169063e6248d5590602401602060405180830381865afa158015613976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399a91906158e2565b815260208082019290925260409081015f9081206001600160a01b038516825290925290205460ff16613525576040516367ee2b0160e11b815260040160405180910390fd5b6139e982613e93565b6387a211a2600c9081525f82905260209020546001600160a01b0382165f90815260056020526040902054613a1f9084906158cf565b11156135255761352563e6c95926613433565b60075464ffffffffff608882901c1642819003613a4d575050565b6009546004546001600160601b0384169164ffffffffff606086901c169160b086901c916001600160f01b0316905f613a888684878a614b3a565b9050844210613bb95760085494965086945f906001600160a01b031663589dc77b613ab161202c565b613abb85886158cf565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160408051808303815f875af1158015613afa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1e9190615d8a565b9097509050808080613b308942615949565b613b3a9190615dac565b613b449190615dcb565b613b4e91906158cf565b9050613b5a81876158cf565b60408051898152602081018390529197507f6ca03c3e1f9f2693eb4277ee4f449b9838fad99c363f5d54bacaf5f71a34afec910160405180910390a1613bab87613ba484876158cf565b888b614b3a565b613bb590836158cf565b9150505b6009545f90613bd7908390600160f01b900461ffff1661271061317a565b90508015613ca1575f613c0f82613bf56805345cdf77eb68f44c5490565b84613c0087896158cf565b613c0a9190615949565b614934565b90505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c6e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c929190615846565b9050613c9e8183614b94565b50505b8115613d305784613cb383878761317a565b613cbd91906158cf565b9450613cc982856158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613cf382846158cf565b60045560408051838152602081018390527f4e32a70f9f06da2cec9f0079d5658935775123a5ce8d0d68de35d019a8d1c19c910160405180910390a15b5050505060609190911b4260881b1760b09190911b176001600160601b0391909116176007555050565b613d6383613e93565b613d6c83614bfd565b6001600160a01b0381165f9081526005602052604090205415613da257604051635d00c4f360e11b815260040160405180910390fd5b5f83613dad83610d80565b613db791906158cf565b6007546001600160a01b0384165f908152600a602052604090206001600160b01b0319909116821790559050600954613dfa9085906001600160f01b03166158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613e457f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b98486613220565b60408051858152602081018390526001600160a01b0384168183015290517fbec1750eb40c00e8dc2e1c84babbddd5779eaa06c951ab2c66416d05910e7a739181900360600190a150505050565b80613ea55763c0883a555f526004601cfd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716613eea57637939f4245f526004601cfd5b5f60605260405250505050565b8260601b6387a211a28117600c526020600c20805480841115613f215763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a350505050565b60405163de0c7a7160e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063de0c7a71906024016131ce565b611770811115613fc057613fc0638b5fe5a3613433565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b91016136a6565b5f61402c613a32565b5f614035612d37565b90505f61404f6140458984612d4d565b9350838784614433565b905084156140665761406186336138fd565b614070565b6140708689614c25565b6001600160a01b038681165f90815260056020526040808220549051632076d8e760e01b815291927f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b1691632076d8e7916140d79130918e918d9189918d90600401615d51565b6020604051808303815f875af11580156140f3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061411791906158e2565b90508015614129576141298188613616565b614136848a338b8b614478565b50505095945050505050565b5f61414b613a32565b5f614154612d37565b90505f614162878684614433565b905061417a856141728985612d80565b945084614c25565b6001600160a01b038581165f90815260056020526040808220549051632076d8e760e01b815291927f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b1691632076d8e7916141e191309189918c9189918d90600401615d51565b6020604051808303815f875af11580156141fd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061422191906158e2565b90508015614233576142338187613616565b6142408885338a8a614478565b505050949350505050565b6008546040805163ea12489f60e01b8152905130926001600160a01b03169163ea12489f9160048083019260209291908290030181865afa158015614292573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142b69190615846565b6001600160a01b0316146142d1576142d163471656c5613433565b6142da81614c40565b60b0670de0b6b3a7640000901b608842901b606042901b6001600160601b036007541617171760078190555050565b5f614312613a32565b61431b83613e93565b6040516330ae91d160e21b81523060048201527f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b6001600160a01b03169063c2ba4744906024015f604051808303815f87803b158015614379575f5ffd5b505af115801561438b573d5f5f3e3d5ffd5b50505050610bc461439e846122cb612d37565b91508184338561498c565b5f6387a211a2600c52335f526020600c208054808411156143d15763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c335f516020615eda5f395f51905f52602080a350600192915050565b5f5f6144206805345cdf77eb68f44c5490565b90508015612d7857612d73848483614934565b5f61443d84613e93565b506387a211a2600c9081525f839052602090205461445b8183612d4d565b84111561446f5761446f63e6c95926613433565b61141a84614bfd565b6144828185614d01565b61448b85614d62565b6144b67f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b98387613220565b806001600160a01b0316826001600160a01b0316846001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db888860405161450e929190918252602082015260400190565b60405180910390a45050505050565b604051632748468360e11b81523390634e908d0690614546903090899088908790600401615de2565b5f604051808303815f87803b15801561455d575f5ffd5b505af115801561456f573d5f5f3e3d5ffd5b50506387a211a2600c9081525f869052602090205461459192508691506158cf565b82146145b05760405163350385ad60e11b815260040160405180910390fd5b6001600160a01b038381165f90815260056020526040808220549051632076d8e760e01b815291927f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b1691632076d8e7916146179130918a918a918a918990600401615d51565b6020604051808303815f875af1158015614633573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465791906158e2565b90508015614669576146698185613616565b505050505050565b5f5f6146846805345cdf77eb68f44c5490565b90508015612d7857612d73848285614898565b6146a881638ec124b360e01b614d76565b6146b9576146b9638b5fe5a3613433565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa158015614718573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061473c91906158e2565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a032906060015b60405180910390a1505050565b60605f5f846001600160a01b03165f856040516147b29190615ec3565b5f6040518083038185875af1925050503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b606091505b5091509150614801858383614d91565b95945050505050565b60605f5f846001600160a01b0316846040516148269190615ec3565b5f60405180830381855af49150503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b6007546009545f9190612076906001600160601b038316906001600160f01b031664ffffffffff606085901c811690608886901c16614b3a565b8282025f1983850981811082019003806148c757826148be5763ae47f7025f526004601cfd5b5081900461141a565b8083116148db5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f614940848484614898565b9050818385091561141a576001018061141a5763ae47f7025f526004601cfd5b5f825f19048411830215820261497d5763ad251c275f526004601cfd5b50910281810615159190040190565b6149b87f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b9833087613ea8565b6149c184614dd9565b6149cb8184614b94565b806001600160a01b0316826001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78686604051614a19929190918252602082015260400190565b60405180910390a3613610565b5f82600154614a3591906158cf565b6040516301ac71bb60e11b81523060048201526001600160a01b038481166024830152604482018390529192507f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b90911690630358e376906064015f604051808303815f87803b158015614aa7575f5ffd5b505af1158015614ab9573d5f5f3e3d5ffd5b5050506001600160a01b0383165f90815260056020526040902054614ae0915084906158cf565b6001600160a01b0383165f818152600560209081526040918290209390935560018481558151878152938401528201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda690606001614788565b5f5f85118015614b4957508282105b15610dc757614801834210614b7157614b628385615949565b614b6c9087615dcb565b614b85565b614b7b8342615949565b614b859087615dcb565b85670de0b6b3a7640000614de7565b6805345cdf77eb68f44c5481810181811015614bb75763e5cfe9575f526004601cfd5b806805345cdf77eb68f44c5550506387a211a2600c52815f526020600c208181540181555080602052600c5160601c5f5f516020615eda5f395f51905f52602080a35050565b80614c0661202c565b1015613ea55760405163ab2169c760e01b815260040160405180910390fd5b336001600160a01b0383161461352557613525823383614df3565b336001600160a01b037f000000000000000000000000e5970cdb1916b2ccf6185c86c174eee2d330d05b1614614c7d57614c7d63471656c5613433565b3062012fd1614cae7f000000000000000000000000a3227c5969757783154c60bf0bc1944180ed81b9848484613ea8565b80614cb95f82614b94565b600482905560408051838152602081018390525f916001600160a01b038716917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101614a19565b6387a211a2600c52815f526020600c20805480831115614d285763f4d678b85f526004601cfd5b82900390556805345cdf77eb68f44c805482900390555f8181526001600160a01b0383165f516020615eda5f395f51905f52602083a35050565b80600454614d709190615949565b60045550565b5f614d8083614e31565b801561141a575061141a8383614e63565b6060614d9d8383614ee9565b8151158015614db457506001600160a01b0384163b155b15614dd2576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b80600454614d7091906158cf565b5f610dc7848484614f17565b81602052637f5e9f20600c52825f526034600c20805460018101156133855780831115614e27576313be252b5f526004601cfd5b9190910390555050565b5f614e43826301ffc9a760e01b614e63565b8015610bc45750614e5c826001600160e01b0319614e63565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015614ed3575060208210155b8015614ede57505f81115b979650505050505050565b816135255780515f03614f0f576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f825f190484118302158202614f345763ad251c275f526004601cfd5b5091020490565b5f60208284031215614f4b575f5ffd5b81356001600160e01b03198116811461141a575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61141a6020830184614f62565b5f60208284031215614fb2575f5ffd5b5035919050565b6001600160a01b0381168114613ea5575f5ffd5b5f5f60408385031215614fde575f5ffd5b8235614fe981614fb9565b946020939093013593505050565b5f5f83601f840112615007575f5ffd5b5081356001600160401b0381111561501d575f5ffd5b6020830191508360208260051b8501011115615037575f5ffd5b9250929050565b5f5f5f60408486031215615050575f5ffd5b83356001600160401b03811115615065575f5ffd5b61507186828701614ff7565b909450925050602084013561508581614fb9565b809150509250925092565b5f602082840312156150a0575f5ffd5b813561141a81614fb9565b5f5f5f606084860312156150bd575f5ffd5b83356150c881614fb9565b925060208401356150d881614fb9565b929592945050506040919091013590565b5f5f604083850312156150fa575f5ffd5b82359150602083013561510c81614fb9565b809150509250929050565b5f5f5f5f5f6060868803121561512b575f5ffd5b85356001600160401b03811115615140575f5ffd5b61514c88828901614ff7565b90965094505060208601356001600160401b0381111561516a575f5ffd5b61517688828901614ff7565b909450925050604086013561518a81614fb9565b809150509295509295909350565b5f5f5f604084860312156151aa575f5ffd5b8335925060208401356001600160401b038111156151c6575f5ffd5b8401601f810186136151d6575f5ffd5b80356001600160401b038111156151eb575f5ffd5b8660208284010111156151fc575f5ffd5b939660209190910195509293505050565b5f5f5f5f5f60608688031215615221575f5ffd5b85356001600160401b03811115615236575f5ffd5b61524288828901614ff7565b909650945050602086013561525681614fb9565b925060408601356001600160401b03811115615270575f5ffd5b61527c88828901614ff7565b969995985093965092949392505050565b5f5f5f6060848603121561529f575f5ffd5b8335925060208401356152b181614fb9565b9150604084013561508581614fb9565b5f5f604083850312156152d2575f5ffd5b82356152dd81614fb9565b9150602083013561510c81614fb9565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b0381118282101715615323576153236152ed565b60405290565b604051606081016001600160401b0381118282101715615323576153236152ed565b604051601f8201601f191681016001600160401b0381118282101715615373576153736152ed565b604052919050565b8035610c8981614fb9565b5f82601f830112615395575f5ffd5b81356001600160401b038111156153ae576153ae6152ed565b6153c1601f8201601f191660200161534b565b8181528460208386010111156153d5575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c08284031215615401575f5ffd5b615409615301565b9050813561541681614fb9565b815260208281013590820152604082013561543081614fb9565b6040820152606082013561544381614fb9565b60608201526080828101359082015260a08201356001600160401b0381111561546a575f5ffd5b61547684828501615386565b60a08301525092915050565b5f5f5f60608486031215615494575f5ffd5b8335925060208401356154a681614fb9565b915060408401356001600160401b038111156154c0575f5ffd5b840160c081870312156154d1575f5ffd5b6154d9615301565b6154e28261537b565b8152602082810135908201526154fa6040830161537b565b60408201526060828101359082015260808201356001600160401b03811115615521575f5ffd5b61552d888285016153f1565b60808301525060a08201356001600160401b0381111561554b575f5ffd5b61555788828501615386565b60a08301525080925050509250925092565b5f6001600160401b03821115615581576155816152ed565b5060051b60200190565b5f82601f83011261559a575f5ffd5b81356155ad6155a882615569565b61534b565b8082825260208201915060208360051b8601019250858311156155ce575f5ffd5b602085015b8381101561560e5780356001600160401b038111156155f0575f5ffd5b6155ff886020838a01016153f1565b845250602092830192016155d3565b5095945050505050565b5f5f5f6060848603121561562a575f5ffd5b83359250602084013561563c81614fb9565b915060408401356001600160401b03811115615656575f5ffd5b840160c08187031215615667575f5ffd5b61566f615301565b6156788261537b565b8152602082810135908201526156906040830161537b565b60408201526060828101359082015260808201356001600160401b038111156156b7575f5ffd5b61552d8882850161558b565b8015158114613ea5575f5ffd5b5f5f604083850312156156e1575f5ffd5b82356156ec81614fb9565b9150602083013561510c816156c3565b5f5f5f5f5f5f5f60e0888a031215615712575f5ffd5b873561571d81614fb9565b9650602088013561572d81614fb9565b95506040880135945060608801359350608088013560ff81168114615750575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f6020838503121561577e575f5ffd5b82356001600160401b03811115615793575f5ffd5b61579f85828601614ff7565b90969095509350505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561580257603f198786030184526157ed858351614f62565b945060209384019391909101906001016157d1565b50929695505050505050565b600181811c9082168061582257607f821691505b60208210810361584057634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215615856575f5ffd5b815161141a81614fb9565b5f60208284031215615871575f5ffd5b815161141a816156c3565b634e487b7160e01b5f52601160045260245ffd5b5f5f5f606084860312156158a2575f5ffd5b83516158ad816156c3565b60208501519093506158be816156c3565b6040850151909250615085816156c3565b80820180821115610bc457610bc461587c565b5f602082840312156158f2575f5ffd5b5051919050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610bc457610bc461587c565b80516001600160a01b03908116835260208083015190840152604080830151821690840152606080830151909116908301526080808201519083015260a08181015160c09184018290525f91610dc790850182614f62565b60018060a01b038516815283602082015260018060a01b03831660408201526080606082015260018060a01b038251166080820152602082015160a082015260018060a01b0360408301511660c0820152606082015160e08201525f608083015160c0610100840152615a2b61014084018261595c565b905060a0840151607f1984830301610120850152615a498282614f62565b98975050505050505050565b5f8235605e19833603018112615a69575f5ffd5b9190910192915050565b5f60608236031215615a83575f5ffd5b615a8b615329565b8235615a9681614fb9565b81526020830135615aa6816156c3565b602082015260408301356001600160401b03811115615ac3575f5ffd5b615acf36828601615386565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061480190830184614f62565b5f8151808452602084019350602083015f5b82811015615b36578151865260209586019590910190600101615b18565b5093949350505050565b8183526020830192505f815f5b84811015615b36578135615b6081614fb9565b6001600160a01b031686526020958601959190910190600101615b4d565b61014081525f615b92610140830188615b06565b6001600160a01b03871660208401528281036040840152615bb4818688615b40565b91505060018060a01b03835116606083015260018060a01b036020840151166080830152604083015160a08301526060830151151560c0830152608083015160e083015260a083015161010083015260c08301516101208301529695505050505050565b5f82601f830112615c27575f5ffd5b8151615c356155a882615569565b8082825260208201915060208360051b860101925085831115615c56575f5ffd5b602085015b8381101561560e578051835260209283019201615c5b565b5f5f60408385031215615c84575f5ffd5b82516001600160401b03811115615c99575f5ffd5b830160608186031215615caa575f5ffd5b615cb2615329565b81516001600160401b03811115615cc7575f5ffd5b615cd387828501615c18565b8252506020828101518183015260409283015192820192909252908401519092506001600160401b03811115615d07575f5ffd5b615d1385828601615c18565b9150509250929050565b606081525f615d2f6060830187615b06565b6001600160a01b03861660208401528281036040840152614ede818587615b40565b6001600160a01b03968716815260208101959095529290941660408401526060830152608082019290925290151560a082015260c00190565b5f5f60408385031215615d9b575f5ffd5b505080516020909101519092909150565b5f82615dc657634e487b7160e01b5f52601260045260245ffd5b500490565b8082028115828204841417610bc457610bc461587c565b60018060a01b038516815283602082015260018060a01b0383166040820152608060608201525f610140820160018060a01b038451166080840152602084015160a084015260018060a01b0360408501511660c0840152606084015160e0840152608084015160c0610100850152818151808452610160860191506101608160051b87010193506020830192505f5b81811015615ea35761015f19878603018352615e8e85855161595c565b94506020938401939290920191600101615e71565b5050505060a0840151838203607f1901610120850152615a498282614f62565b5f82518060208501845e5f92019182525091905056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122074fb7caf678ec10c7ddfffe1fc72b7e28011c552aa37a2b16c4ca7bf2a51e55864736f6c634300081c0033
Deployed Bytecode Sourcemap
254846:43078:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;220849:147;;;:::i;:::-;;;160:25:1;;;148:2;133:18;220849:147:0;;;;;;;;220414:292;;;;;;:::i;:::-;;:::i;:::-;;;652:14:1;;645:22;627:41;;615:2;600:18;220414:292:0;487:187:1;213018:92:0;;;:::i;:::-;;;;;;;:::i;221870:182::-;;;;;;:::i;:::-;;:::i;10210:586::-;;;;;;:::i;:::-;;:::i;223198:173::-;;;;;;:::i;:::-;;:::i;269024:539::-;;;;;;:::i;:::-;;:::i;:::-;;274659:743;;;;;;:::i;:::-;;:::i;255265:41::-;;255305:1;255265:41;;9026:200;9189:18;9183:25;9026:200;;272412:305;;;:::i;256161:22::-;;;;;-1:-1:-1;;;;;256161:22:0;;;;;;-1:-1:-1;;;;;3321:32:1;;;3303:51;;3291:2;3276:18;256161:22:0;3138:222:1;273884:482:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;3600:13:1;;-1:-1:-1;;;;;3596:39:1;;;3578:58;;3696:4;3684:17;;;3678:24;3674:50;;;3652:20;;;3645:80;3785:4;3773:17;;;3767:24;3793:4;3763:35;3741:20;;;3734:65;3869:4;3857:17;;;3851:24;3844:32;3837:40;3815:20;;;3808:70;3934:4;3922:17;;;3916:24;3894:20;;;3887:54;3623:3;3985:17;;;3979:24;3957:20;;;3950:54;;;;3565:3;3550:19;;3365:645;219557:315:0;;;;;;:::i;:::-;;:::i;202513:599::-;;;;;;:::i;:::-;;:::i;113683:204::-;;;5072:4:1;240971:9:0;5060:17:1;5042:36;;5030:2;5015:18;113683:204:0;4900:184:1;207697:175:0;;;;;;:::i;:::-;;:::i;19805:707::-;;;:::i;266714:110::-;;;;;;:::i;:::-;;:::i;268045:517::-;;;;;;:::i;:::-;;:::i;213437:106::-;213528:6;213437:106;;211455:131;;;:::i;213890:467::-;;;;;;:::i;:::-;;:::i;207249:246::-;;;;;;:::i;:::-;;:::i;196627:45::-;;;;;277014:99;277101:4;277014:99;;261838:550;;;;;;:::i;:::-;;:::i;223662:171::-;;;;;;:::i;:::-;;:::i;206662:169::-;;;;;;:::i;:::-;;:::i;270012:812::-;;;;;;:::i;:::-;;:::i;209100:1695::-;;;;;;:::i;:::-;;:::i;271737:225::-;;;;;;:::i;:::-;;:::i;261254:229::-;;;;;;:::i;:::-;;:::i;218226:220::-;;;;;;:::i;:::-;;:::i;143141:223::-;;;;;;:::i;:::-;;:::i;256450:36::-;;;;;-1:-1:-1;;;;;256450:36:0;;;;;;-1:-1:-1;;;;;9301:32:1;;;9283:51;;9271:2;9256:18;256450:36:0;9137:203:1;263085:638:0;;;;;;:::i;:::-;;:::i;206160:231::-;;;;;;:::i;:::-;;:::i;215495:184::-;;;;;;:::i;:::-;;:::i;9295:293::-;;;;;;:::i;:::-;9466:18;9460:4;9453:32;;;9358:14;9499:19;;;;9564:4;9548:21;;9542:28;;9295:293;204713:226;;;;;;:::i;:::-;;:::i;252521:28::-;;;;;;224017:84;;;:::i;199536:157::-;;;;;;:::i;:::-;;:::i;259426:567::-;;;:::i;:::-;;;;9576:25:1;;;9632:2;9617:18;;9610:34;;;;9660:18;;;9653:34;9718:2;9703:18;;9696:34;9563:3;9548:19;259426:567:0;9345:391:1;15899:348:0;;;;;;:::i;:::-;16126:17;16120:4;16113:31;;;15959:14;16158:19;;;;16223:4;16207:21;;16201:28;;15899:348;255092:55;;255143:4;255092:55;;265054:1359;;;;;;:::i;:::-;;:::i;276039:774::-;;;:::i;139783:49::-;;;;;216098:178;;;;;;:::i;:::-;;:::i;213210:96::-;;;:::i;143762:178::-;;;;;;:::i;:::-;;:::i;267216:123::-;;;;;;:::i;:::-;;:::i;256606:25::-;;;;;-1:-1:-1;;;256606:25:0;;;;;;;;;14264:6:1;14252:19;;;14234:38;;14222:2;14207:18;256606:25:0;14090:188:1;275619:130:0;;;;;;:::i;:::-;;:::i;218804:281::-;;;;;;:::i;:::-;;:::i;208195:252::-;;;;;;:::i;:::-;;:::i;271125:237::-;;;:::i;203781:468::-;;;;;;:::i;:::-;;:::i;222770:157::-;;;;;;:::i;:::-;;:::i;216745:224::-;;;;;;:::i;:::-;;:::i;217447:227::-;;;;;;:::i;:::-;;:::i;200986:1000::-;;;;;;:::i;:::-;;:::i;141431:666::-;;;;;;:::i;:::-;;:::i;221342:182::-;;;;;;:::i;:::-;;:::i;205381:229::-;;;;;;:::i;:::-;;:::i;127420:148::-;;;;;;:::i;:::-;;:::i;211929:188::-;;;;;;:::i;:::-;;:::i;260384:497::-;;;;;;:::i;:::-;;:::i;16437:3284::-;;;;;;:::i;:::-;;:::i;127912:129::-;;;;;;:::i;:::-;;:::i;9686:388::-;;;;;;:::i;:::-;9909:4;9902:21;9950:20;9944:4;9937:34;;;9802:14;9985:19;;;;10050:4;10034:21;;10028:28;;9686:388;197025:37;;;;;;197473:51;;;;;;:::i;:::-;;;;;;;;;;;;;;142479:163;;;;;;:::i;:::-;;:::i;137191:1590::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;222303:164::-;;;;;;:::i;:::-;;:::i;273130:387::-;;;:::i;211092:171::-;;;:::i;220849:147::-;220929:14;84124:22;84118:29;84115:146;;;84180:10;84174:4;84167:24;84241:4;84235;84228:18;84115:146;220971:17:::1;:15;:17::i;:::-;220962:26;;220849:147:::0;:::o;220414:292::-;220515:11;-1:-1:-1;;;;;;220548:40:0;;-1:-1:-1;;;220548:40:0;;:97;;-1:-1:-1;;;;;;;220605:40:0;;-1:-1:-1;;;220605:40:0;220548:97;:150;;;-1:-1:-1;;;;;;;;;;104217:40:0;;;220662:36;220539:159;220414:292;-1:-1:-1;;220414:292:0:o;213018:92::-;213064:13;213097:5;213090:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;213018:92;:::o;221870:182::-;221974:7;84124:22;84118:29;84115:146;;;84180:10;84174:4;84167:24;84241:4;84235;84228:18;84115:146;222001:43:::1;222018:6;222026:17;:15;:17::i;:::-;222001:16;:43::i;84282:1::-;221870:182:::0;;;:::o;10210:586::-;10284:4;10447:7;10441:4;10434:21;10482:20;10476:4;10469:34;10530:8;10524:4;10517:22;10583:6;10576:4;10570;10560:21;10553:37;10660:6;10654:4;10647:20;10749:4;10743:11;10739:2;10735:20;10725:8;10698:25;10692:4;10686;10681:75;-1:-1:-1;10784:4:0;10210:586;;;;:::o;223198:173::-;223293:7;223320:43;223337:6;223345:17;:15;:17::i;:::-;223320:16;:43::i;269024:539::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;269177:8;269155:19:::1;269177:8:::0;-1:-1:-1;;;;;269337:26:0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;269337:26:0::1;;269306:57;;269384:171;269409:11;269435:10;269460:8;;269483:15;269513:11;269539:5;269384:10;:171::i;:::-;269144:419;;83908:1:::0;83884:22;83877:33;269024:539;;;:::o;274659:743::-;-1:-1:-1;;;;;274832:16:0;;274718:9;274832:16;;;:7;:16;;;;;;-1:-1:-1;;;;;274859:41:0;;274999:20;;;274995:61;;275036:8;;274659:743;;;:::o;274995:61::-;275297:12;;275236:158;;275260:15;;255813:3;275297:34;;;;275354:28;;;275236:9;:158::i;:::-;275232:162;274659:743;-1:-1:-1;;;;274659:743:0:o;272412:305::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;272461:22:::1;:20;:22::i;:::-;272494:14;272511:15;:13;:15::i;:::-;272494:32;;272539:18;272560:15;-1:-1:-1::0;;;;;272560:26:0::1;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;272539:49:::0;-1:-1:-1;272599:57:0::1;213528:6:::0;272637:10:::1;272649:6;272599:28;:57::i;:::-;272674:35;::::0;;20432:25:1;;;-1:-1:-1;;;;;20493:32:1;;20488:2;20473:18;;20466:60;272674:35:0::1;::::0;20405:18:1;272674:35:0::1;;;;;;;272450:267;;83908:1:::0;83884:22;83877:33;272412:305::o;273884:482::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;274036:20:0;274048:7;274036:11;:20::i;:::-;274092:4;274069:28;;-1:-1:-1;;;;;274136:6:0;274108:35;:17;;;:35;274010:46;-1:-1:-1;240971:9:0;274154:28;;:15;;;:28;274215:19;:34;;274245:4;274215:34;;;274237:5;274215:34;274193:56;;:19;;;:56;-1:-1:-1;;;;;274286:25:0;;;;;;;:16;:25;;;;;;274260:23;;;:51;274322:18;;;:36;;;;274193:6;273884:482::o;219557:315::-;219700:4;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;219717:39:::1;219732:6;219740:8;219750:5;219717:14;:39::i;:::-;219799:43;219818:5;219825:8;219835:6;219799:18;:43::i;:::-;;219860:4;219853:11;;83908:1:::0;83884:22;83877:33;219557:315;;;;;:::o;202513:599::-;202632:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;202677:10:::1;-1:-1:-1::0;;;;;202677:22:0;::::1;;::::0;::::1;::::0;:83:::1;;-1:-1:-1::0;202717:43:0::1;::::0;-1:-1:-1;;;202717:43:0;;202749:10:::1;202717:43;::::0;::::1;3303:51:1::0;202717:13:0::1;-1:-1:-1::0;;;;;202717:31:0::1;::::0;::::1;::::0;3276:18:1;;202717:43:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;202716:44;202677:83;202659:171;;;202787:31;195673:10;202787:7;:31::i;:::-;202851:26;202860:6;202868:8;202851;:26::i;:::-;202842:35;;203071:33;203087:6;203095:8;203071:15;:33::i;:::-;83908:1:::0;83884:22;83877:33;202513:599;;;;:::o;207697:175::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;207772:42:::1;207795:6;207803:10;207772:22;:42::i;:::-;207827:37;207845:6;207853:10;207827:17;:37::i;:::-;83908:1:::0;83884:22;83877:33;207697:175;:::o;19805:707::-;19862:14;;20088:6;:4;:6::i;:::-;20072:24;;;;;;20061:35;;20190:4;20184:11;20252:16;20249:1;20242:27;20304:8;20297:4;20294:1;20290:12;20283:30;20348:13;20341:4;20338:1;20334:12;20327:35;20397:9;20390:4;20387:1;20383:12;20376:31;20442:9;20435:4;20432:1;20428:12;20421:31;20489:4;20486:1;20476:18;20466:28;;;20160:345;19805:707;:::o;266714:110::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;266778:38:::1;266785:6;266793:10;266805;266778:6;:38::i;:::-;;83908:1:::0;83884:22;83877:33;266714:110;:::o;268045:517::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;268244:8;268274:33;;::::1;268270:102;;268324:36;255960:10;268324:7;:36::i;:::-;268384:170;268409:11;;268384:170;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;268435:10:0::1;::::0;-1:-1:-1;268460:8:0;;-1:-1:-1;268460:8:0;;-1:-1:-1;268483:15:0;268513:11;268539:4:::1;268384:10;:170::i;:::-;268211:351;83908:1:::0;83884:22;83877:33;268045:517;;;;;:::o;211455:131::-;211502:14;211538:40;636:4;211560:17;:15;:17::i;213890:467::-;214028:42;;-1:-1:-1;;;214028:42:0;;214064:4;214028:42;;;3303:51:1;213974:17:0;;;;-1:-1:-1;;;;;214028:13:0;:27;;;;3276:18:1;;214028:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;214086:37:0;;-1:-1:-1;;;214086:37:0;;214117:4;214086:37;;;3303:51:1;214004:66:0;;-1:-1:-1;214086:13:0;-1:-1:-1;;;;;214086:22:0;;;;3276:18:1;;214086:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;214085:38;:52;;;;214127:10;214085:52;214081:220;;;214273:16;213890:467;;;:::o;214081:220::-;-1:-1:-1;;214323:26:0;214311:38;213890:467;-1:-1:-1;;;213890:467:0:o;207249:246::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;207365:33:::1;207380:5;207387:10;207365:14;:33::i;:::-;207409:35;207430:6;207438:5;207409:20;:35::i;:::-;207457:30;207473:6;207481:5;207457:15;:30::i;:::-;83908:1:::0;83884:22;83877:33;207249:246;;:::o;261838:550::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;261960:17:::1;:15;:17::i;:::-;262289:21;::::0;-1:-1:-1;;;;;262167:13:0::1;:33;::::0;::::1;::::0;262223:4:::1;::::0;262243:6;;262264:10:::1;::::0;262289:30:::1;::::0;262243:6;;-1:-1:-1;;;;;262289:21:0::1;:30;:::i;:::-;262167:163;::::0;-1:-1:-1;;;;;;262167:163:0::1;::::0;;;;;;-1:-1:-1;;;;;21957:32:1;;;262167:163:0::1;::::0;::::1;21939:51:1::0;22006:18;;;21999:34;;;;22069:32;;22049:18;;;22042:60;22118:18;;;22111:34;;;;21911:19;;262167:163:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;262343:37;262351:6;262359:8;262369:10;262343:7;:37::i;223662:171::-:0;223755:7;223782:43;223799:6;223807:17;:15;:17::i;206662:169::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;206735:40:::1;206756:6;206764:10;206735:20;:40::i;:::-;206788:35;206804:6;206812:10;206788:15;:35::i;270012:812::-:0;270088:17;:15;:17::i;:::-;270118:24;270135:6;270118:16;:24::i;:::-;270166:31;;-1:-1:-1;;;270166:31:0;;270191:4;270166:31;;;3303:51:1;270166:6:0;-1:-1:-1;;;;;270166:16:0;;;;3276:18:1;;270166:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;270157:6;:40;270153:122;;;270221:42;;-1:-1:-1;;;270221:42:0;;;;;;;;;;;270153:122;270311:6;270287:13;270343:16;270352:6;270343:8;:16::i;:::-;270329:30;-1:-1:-1;270370:22:0;270395:12;270329:30;270395:6;:12;:::i;:::-;270370:37;;270428:55;270457:5;270464:10;270476:6;270428:28;:55::i;:::-;270496:64;;-1:-1:-1;;;270496:64:0;;270507:10;;270496:34;;:64;;270531:6;;270539:14;;270555:4;;;;270496:64;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;270573:145;270620:5;270640:10;270673:4;270693:14;270573:32;:145::i;:::-;270761:3;270746:12;;:18;;;;:::i;:::-;270731:12;:33;270782:34;;;23320:25:1;;;23376:2;23361:18;;23354:34;;;270805:10:0;23404:18:1;;;23397:60;270782:34:0;;;;;;;23308:2:1;270782:34:0;;;270077:747;;;270012:812;;;:::o;209100:1695::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;209310:49:::1;::::0;-1:-1:-1;;;209310:49:0;;209341:4:::1;209310:49;::::0;::::1;23642:51:1::0;209348:10:0::1;23709:18:1::0;;;23702:60;209310:13:0::1;-1:-1:-1::0;;;;;209310:22:0::1;::::0;::::1;::::0;23615:18:1;;209310:49:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;209594:8:0;;-1:-1:-1;209572:19:0::1;::::0;-1:-1:-1;209572:19:0;;-1:-1:-1;209572:19:0;;209703:918:::1;209723:11;209719:1;:15;209703:918;;;209765:16;;209782:1;209765:19;;;;;;;:::i;:::-;;;;;;;209756:28;;209900:6;209910:1;209900:11:::0;209896:60;209932:8:::1;209896:60;209982:8;;209991:1;209982:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;209972:21;;210124;210139:6:::0;210124:21;::::1;:::i;:::-;-1:-1:-1::0;;;;;210305:25:0;::::1;;::::0;;;:16:::1;:25;::::0;;;;;210124:21;;-1:-1:-1;210305:34:0::1;::::0;210333:6;;210305:34:::1;:::i;:::-;-1:-1:-1::0;;;;;210277:25:0;::::1;;::::0;;;:16:::1;:25;::::0;;;;;;;:62;;;;210359:41;;24234:25:1;;;24275:18;;;24268:50;;;;24334:18;;;24327:60;210359:41:0::1;::::0;24222:2:1;24207:18;210359:41:0::1;;;;;;;210492:58;210522:7;210531:10;210543:6;210492:29;:58::i;:::-;210570:39;::::0;;24600:25:1;;;-1:-1:-1;;;;;24661:32:1;;;24656:2;24641:18;;24634:60;24730:32;;24710:18;;;24703:60;210570:39:0;;::::1;::::0;;;;24588:2:1;210570:39:0;;::::1;209703:918;209736:3;;209703:918;;;;210776:11;210751:22;;:36;;;;:::i;:::-;210726:22;:61:::0;-1:-1:-1;83908:1:0;;-1:-1:-1;83884:22:0;;-1:-1:-1;;83877:33:0;209100:1695;;;;;:::o;271737:225::-;271829:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;271895:17:::1;:15;:17::i;:::-;271934:20;271946:7;271934:11;:20::i;:::-;271925:29;;83908:1:::0;83884:22;83877:33;271737:225;;;:::o;261254:229::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;261335:27:::1;:25;:27::i;:::-;261414:17;:15;:17::i;:::-;261444:31;261460:14;261444:15;:31::i;218226:220::-:0;218357:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;218393:45:::1;218401:6;218409:8;218419:5;218426:4;218432:5;218393:7;:45::i;:::-;218384:54;;83908:1:::0;83884:22;83877:33;218226:220;;;;;:::o;143141:223::-;-1:-1:-1;;;;;143274:17:0;;;143241:11;143274:17;;;;;;;;;;;143292:53;;-1:-1:-1;;;143292:53:0;;;;;3303:51:1;;;;143241:11:0;;143274:17;;143241:11;;143292:15;:47;;;;3276:18:1;;143292:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;143274:72;;;;;;;;;;;;;;-1:-1:-1;143274:72:0;;;-1:-1:-1;;;;;143274:82:0;;;;;;;;;;;;;;;;143141:223;-1:-1:-1;;143141:223:0:o;263085:638::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;263220:33:::1;263235:5;263242:10;263220:14;:33::i;:::-;263305:17;:15;:17::i;:::-;263629:21;::::0;-1:-1:-1;;;;;263512:13:0::1;:33;::::0;::::1;::::0;263568:4:::1;::::0;263588:6;;263609:5;;263629:30:::1;::::0;263588:6;;-1:-1:-1;;;;;263629:21:0::1;:30;:::i;:::-;263512:158;::::0;-1:-1:-1;;;;;;263512:158:0::1;::::0;;;;;;-1:-1:-1;;;;;21957:32:1;;;263512:158:0::1;::::0;::::1;21939:51:1::0;22006:18;;;21999:34;;;;22069:32;;22049:18;;;22042:60;22118:18;;;22111:34;;;;21911:19;;263512:158:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;263683:32;263691:6;263699:8;263709:5;263683:7;:32::i;:::-;83908:1:::0;83884:22;83877:33;263085:638;;;:::o;206160:231::-;206303:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;206339:44:::1;206347:6;206355:8;206365:5;206372:4;206378::::0;206339:7:::1;:44::i;215495:184::-:0;215609:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;215645:26:::1;215654:6;215662:8;215645;:26::i;:::-;215636:35;;83908:1:::0;83884:22;83877:33;215495:184;;;;:::o;204713:226::-;204855:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;204891:40:::1;204901:6;204909:8;204919:5;204926:4;204891:9;:40::i;224017:84::-:0;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;224076:17:::1;:15;:17::i;:::-;83908:1:::0;83884:22;83877:33;224017:84::o;199536:157::-;199623:4;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;199640:23:::1;199660:2;199640:19;:23::i;:::-;-1:-1:-1::0;199681:4:0::1;83908:1:::0;83884:22;83877:33;199536:157;;;:::o;259426:567::-;259507:19;259537:18;259566:24;259601:17;84124:22;84118:29;84115:146;;;84180:10;84174:4;84167:24;84241:4;84235;84228:18;84115:146;-1:-1:-1;;259732:12:0::1;::::0;-1:-1:-1;;;;;259755:33:0;::::1;::::0;259799:52:::1;255556:2;259819:31:::0;;::::1;259799:52:::0;::::1;::::0;-1:-1:-1;255676:3:0::1;259888:32:::0;;::::1;259862:59;::::0;-1:-1:-1;255813:3:0::1;259951:33:::0;;;::::1;::::0;259426:567::o;265054:1359::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;265238:43:::1;::::0;-1:-1:-1;;;265238:43:0;;265270:10:::1;265238:43;::::0;::::1;3303:51:1::0;265238:13:0::1;-1:-1:-1::0;;;;;265238:31:0::1;::::0;::::1;::::0;3276:18:1;;265238:43:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;265233:108;;265298:31;195673:10;265298:7;:31::i;:::-;265674:17;:15;:17::i;:::-;265838:48;::::0;-1:-1:-1;;;265838:48:0;;265873:4:::1;265838:48;::::0;::::1;23642:51:1::0;-1:-1:-1;;;;;23729:32:1;;;23709:18;;;23702:60;265838:13:0::1;:26;::::0;::::1;::::0;23615:18:1;;265838:48:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;265899:34;265907:6;265915:10;265927:5;265899:7;:34::i;:::-;266024:138;::::0;-1:-1:-1;;;266024:138:0;;266041:10:::1;::::0;266024:37:::1;::::0;:138:::1;::::0;266084:4:::1;::::0;266104:6;;266125:5;;266145:6;;266024:138:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;266373:21:0::1;::::0;266271:134:::1;::::0;-1:-1:-1;;;266271:134:0;;266317:4:::1;266271:134;::::0;::::1;26686:51:1::0;266337:1:0::1;26753:18:1::0;;;26746:34;-1:-1:-1;;;;;26816:32:1;;;26796:18;;;26789:60;-1:-1:-1;;;;;266373:21:0;;::::1;26865:18:1::0;;;26858:60;266271:13:0::1;:23:::0;;::::1;::::0;-1:-1:-1;266271:23:0::1;::::0;-1:-1:-1;26658:19:1;;266271:134:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83908:1:::0;83884:22;83877:33;265054:1359;;;:::o;276039:774::-;276133:12;;276082:14;;276160:18;;;276156:100;;276202:42;;-1:-1:-1;;;276202:42:0;;;;;;;;;;;276156:100;276757:21;;196541:5;;276741:37;;-1:-1:-1;;;;;276757:21:0;276741:13;:37;:::i;:::-;:64;;;;:::i;:::-;276732:73;;276098:715;276039:774;:::o;216098:178::-;216209:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;216245:23:::1;216251:6;216259:8;216245:5;:23::i;213210:96::-:0;213258:13;213291:7;213284:14;;;;;:::i;143762:178::-;143884:48;;-1:-1:-1;;;143884:48:0;;-1:-1:-1;;;;;3321:32:1;;;143884:48:0;;;3303:51:1;143851:11:0;;143884:15;:42;;;;;;3276:18:1;;143884:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;267216:123::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;267298:33:::1;267305:6;267313:10;267325:5;267298:6;:33::i;:::-;;83908:1:::0;83884:22;83877:33;267216:123;;:::o;275619:130::-;275674:11;275704:37;275714:6;255305:1;745:3;275704:9;:37::i;218804:281::-;218919:4;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;218936:44:::1;218951:6;218959:8;218969:10;218936:14;:44::i;:::-;219023:32;219038:8;219048:6;219023:14;:32::i;:::-;;219073:4;219066:11;;83908:1:::0;83884:22;83877:33;218804:281;;;;:::o;208195:252::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;208313:33:::1;208328:5;208335:10;208313:14;:33::i;:::-;208357:37;208380:6;208388:5;208357:22;:37::i;:::-;208407:32;208425:6;208433:5;208407:17;:32::i;271125:237::-:0;271223:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;271294:17:::1;:15;:17::i;:::-;-1:-1:-1::0;271333:21:0::1;::::0;-1:-1:-1;;;;;271333:21:0::1;;83884:22:::0;83877:33;271125:237;:::o;203781:468::-;203903:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;203930:36:::1;203945:8;203955:10;203930:14;:36::i;222770:157::-:0;222853:7;222880:39;222893:6;222901:17;:15;:17::i;:::-;222880:12;:39::i;216745:224::-;216884:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;216920::::1;216930:6;216938:8;216948:5;216955;216920:9;:41::i;217447:227::-:0;217584:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;217620:46:::1;217628:6;217636:8;217646:5;217653;217660;217620:7;:46::i;200986:1000::-:0;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;201230:43:::1;::::0;-1:-1:-1;;;201230:43:0;;201262:10:::1;201230:43;::::0;::::1;3303:51:1::0;201230:13:0::1;-1:-1:-1::0;;;;;201230:31:0::1;::::0;::::1;::::0;3276:18:1;;201230:43:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;201225:108;;201290:31;195673:10;201290:7;:31::i;:::-;201345:17;:15;:17::i;:::-;201457:10;201470:17;:15;:17::i;:::-;201457:30;;201498:15;201516:35;201533:6;201541:5;201548:2;201516:16;:35::i;:::-;201498:53;;201638:14;201655:28;201672:6;201680:2;201655:16;:28::i;:::-;201638:45;;201696:63;201713:6;201721;201729:10;201741;201753:5;201696:16;:63::i;:::-;201829:149;201877:6;201898;201919:5;201939:7;201961:6;201829:33;:149::i;:::-;201157:829;;;83908:1:::0;83884:22;83877:33;200986:1000;;;:::o;141431:666::-;141531:10;-1:-1:-1;;;;;141519:22:0;;;141515:96;;141565:34;;-1:-1:-1;;;141565:34:0;;;;;;;;;;;141515:96;141729:54;;-1:-1:-1;;;141729:54:0;;141772:10;141729:54;;;3303:51:1;141729:15:0;-1:-1:-1;;;;;141729:42:0;;;;3276:18:1;;141729:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;141725:131;;;141807:37;;-1:-1:-1;;;141807:37:0;;;;;;;;;;;141725:131;141891:45;;-1:-1:-1;;;141891:45:0;;141925:10;141891:45;;;3303:51:1;141868:20:0;;141891:15;-1:-1:-1;;;;;141891:33:0;;;;3276:18:1;;141891:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;141959:10;141947:11;:23;;;;;;;;;;;:37;;;;;;;;-1:-1:-1;;;;;141947:47:0;;;;;;;;;;;;:60;;-1:-1:-1;;141947:60:0;;;;;;;;;;142025:64;;27097:25:1;;;27138:18;;;27131:50;141947:37:0;;-1:-1:-1;141947:47:0;;142025:64;;27070:18:1;142025:64:0;;;;;;;141504:593;141431:666;;:::o;221342:182::-;221446:7;84124:22;84118:29;84115:146;;;84180:10;84174:4;84167:24;84241:4;84235;84228:18;84115:146;221473:43:::1;221490:6;221498:17;:15;:17::i;:::-;221473:16;:43::i;205381:229::-:0;205521:14;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;205557:45:::1;205565:6;205573:8;205583:5;205590;205597:4;205557:7;:45::i;127420:148::-:0;9466:18;9460:4;9453:32;;;127485:17;9499:19;;;9564:4;9548:21;;;9542:28;127527:33;;221870:182;:::i;211929:188::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;212050:17:0;:15;:17::i;:::-;212089:20;212101:7;212089:11;:20::i;260384:497::-;83584:22;83578:29;83575:146;;;83640:10;83634:4;83627:24;83701:4;83695;83688:18;83575:146;83766:9;83742:22;83735:41;260449:27:::1;:25;:27::i;:::-;260528:17;:15;:17::i;:::-;260741:13;;260712:6;-1:-1:-1::0;;;;;260700:35:0::1;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:54;260696:137;;260778:43;;-1:-1:-1::0;;;260778:43:0::1;;;;;;;;;;;260696:137;260845:28;260865:6;260845:7;:28::i;16437:3284::-:0;16645:16;16844:6;:4;:6::i;:::-;16828:24;;;;;;16817:35;;17024:8;17011:11;17008:25;17005:145;;;17066:10;17060:4;17053:24;17130:4;17124;17117:18;17005:145;17179:4;17173:11;17297:5;17293:2;17289:14;17285:2;17281:23;17272:32;;17345:7;17341:2;17337:16;17333:2;17329:25;17318:36;;17440:39;17434:4;17427:53;17507:5;17501:4;17494:19;17560:4;17554;17544:21;17603:9;17597:16;17683;17680:1;17673:27;17735:8;17728:4;17725:1;17721:12;17714:30;17779:13;17772:4;17769:1;17765:12;17758:35;17828:9;17821:4;17818:1;17814:12;17807:31;17873:9;17866:4;17863:1;17859:12;17852:31;17923:4;17920:1;17910:18;17904:4;17897:32;17994:16;17991:1;17984:27;18046:5;18039:4;18036:1;18032:12;18025:27;18087:7;18080:4;18077:1;18073:12;18066:29;18130:5;18123:4;18120:1;18116:12;18109:27;18171:10;18164:4;18161:1;18157:12;18150:32;18217:8;18210:4;18207:1;18203:12;18196:30;18266:4;18263:1;18253:18;18247:4;18240:32;18363:4;18357;18347:21;18341:4;18334:35;18406:1;18400:4;18396:12;18390:4;18383:26;18436:1;18430:4;18423:15;18465:1;18459:4;18452:15;18526:4;18520;18514;18511:1;18508;18501:5;18490:41;18953:5;18934:16;18928:23;18925:34;18915:162;;18993:10;18987:4;18980:24;19057:4;19051;19044:18;18915:162;19164:18;19146:37;;-1:-1:-1;;;19362:43:0;;19356:4;19349:57;19443:4;19437;19427:21;19420:36;;;19397:7;19565:5;19538:25;-1:-1:-1;19525:4:0;19518:12;;19513:67;19601:4;19594:15;-1:-1:-1;;19672:1:0;19666:4;19659:15;-1:-1:-1;;;;;;16437:3284:0:o;127912:129::-;9466:18;9460:4;9453:32;;;127975:17;9499:19;;;9564:4;9548:21;;;9542:28;128017:16;9295:293;142479:163;142595:39;;-1:-1:-1;;;142595:39:0;;-1:-1:-1;;;;;3321:32:1;;;142595:39:0;;;3303:51:1;142559:14:0;;142595:15;:33;;;;;;3276:18:1;;142595:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;137191:1590::-;137278:22;245205:15;137386:5;;-1:-1:-1;;;;;137419:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;137409:31:0;;-1:-1:-1;137497:1277:0;137517:8;137513:1;:12;137497:1277;;;137560:5;;137566:1;137560:8;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;137547:21;;;:::i;:::-;;;137601:10;:24;;;137597:810;;;137829:17;;137809:38;;-1:-1:-1;;;137809:38:0;;-1:-1:-1;;;;;3321:32:1;;;137809:38:0;;;3303:51:1;137791:15:0;;137809:19;;;;;3276:18:1;;137809:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;137791:56;-1:-1:-1;;;;;;137938:21:0;;137934:105;;137991:28;;-1:-1:-1;;;137991:28:0;;;;;;;;;;;137934:105;138155:17;;138195:15;;;;;138059:170;;-1:-1:-1;;;138059:170:0;;-1:-1:-1;;;;;138059:40:0;;;;;:170;;138122:10;;138155:17;138195:15;138059:170;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;138263:83;138311:10;:17;;;138330:10;:15;;;138263:47;:83::i;:::-;138250:7;138258:1;138250:10;;;;;;;;:::i;:::-;;;;;;:96;;;;138383:8;;;137597:810;138563:17;;-1:-1:-1;;;;;138546:34:0;138554:4;138546:34;138542:108;;138608:26;;-1:-1:-1;;;138608:26:0;;;;;;;;;;;138542:108;138679:83;138739:4;138746:10;:15;;;138679:51;:83::i;:::-;138666:7;138674:1;138666:10;;;;;;;;:::i;:::-;;;;;;:96;;;;137497:1277;137527:3;;137497:1277;;;;137302:1479;;;137191:1590;;;;:::o;222303:164::-;222389:7;222416:43;222433:6;222441:17;:15;:17::i;273130:387::-;273226:12;;;273312:39;;-1:-1:-1;;;273312:39:0;;273345:4;273312:39;;;3303:51:1;;;;273176:14:0;;;;273319:6;-1:-1:-1;;;;;273312:24:0;;;;3276:18:1;;273312:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;273288:21;;:63;;;-1:-1:-1;;;;;273288:21:0;:63;:::i;:::-;273249:102;;273385:12;273366:15;:31;273362:95;;273421:24;;-1:-1:-1;;;273421:24:0;;;;;;;;;;;273362:95;273478:30;273496:12;273478:15;:30;:::i;:::-;273469:39;;273192:325;;273130:387;:::o;211092:171::-;211141:14;211168:17;:15;:17::i;:::-;211215:40;636:4;211237:17;254365:123;254424:9;254465:15;:13;:15::i;:::-;254450:12;;:30;;;;:::i;242741:301::-;242843:14;242870:19;242892:13;9189:18;9183:25;;9026:200;242892:13;242870:35;-1:-1:-1;242927:16:0;;:107;;242981:53;243010:6;243018:2;243022:11;242981:28;:53::i;:::-;242927:107;;;-1:-1:-1;242959:6:0;;242918:116;-1:-1:-1;;242741:301:0:o;244045:303::-;244147:14;244174:19;244196:13;9189:18;9183:25;;9026:200;244196:13;244174:35;-1:-1:-1;244231:16:0;;:109;;244285:55;244316:6;244324:11;244337:2;244285:30;:55::i;281679:3823::-;282073:4;-1:-1:-1;;;;;282046:32:0;;;282042:101;;282095:36;255960:10;282095:7;:36::i;:::-;282194:17;:15;:17::i;:::-;282224:38;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;282224:38:0;282400:13;-1:-1:-1;;;;;282400:26:0;;282441:11;282467:10;282492:8;;282515:323;;;;;;;;282576:15;-1:-1:-1;;;;;282515:323:0;;;;;282629:4;-1:-1:-1;;;;;282515:323:0;;;;;282666:11;282515:323;;;;282712:11;282515:323;;;;;;282760:1;282515:323;;;;282792:1;282515:323;;;;282821:1;282515:323;;;282400:449;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;282400:449:0;;;;;;;;;;;;:::i;:::-;282376:473;-1:-1:-1;282376:473:0;-1:-1:-1;282862:150:0;213528:6;282931:10;282964:4;282984:6;:17;;;282862:32;:150::i;:::-;283057:12;;255813:3;283057:34;283025:22;;;;283185:827;283205:11;283201:1;:15;283185:827;;;283307:11;283319:1;283307:14;;;;;;;;:::i;:::-;;;;;;;283294:27;;283428:10;283442:1;283428:15;283424:64;283464:8;283424:64;283514:8;;283523:1;283514:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;283504:21;;283790:10;283767:20;283779:7;283767:11;:20::i;:::-;:33;;;;:::i;:::-;-1:-1:-1;;;;;294490:16:0;;294085:17;294490:16;;;:7;:16;;;;;294416:18;294412:40;;;294363:104;;294490:28;;283758:42;-1:-1:-1;283954:46:0;;;32815:25:1;;;32871:2;32856:18;;32849:34;;;-1:-1:-1;;;;;32919:32:1;;;32899:18;;;32892:60;;;;32988:32;;;32983:2;32968:18;;32961:60;283954:46:0;;32802:3:1;32787:19;283954:46:0;;;;;;;283185:827;283218:3;;283185:827;;;;284311:6;:22;;;284290:6;:17;;:43;;;;;;;:::i;:::-;;;-1:-1:-1;284372:17:0;;;;284348:21;;-1:-1:-1;;;;;284348:21:0;:41;284344:425;;;284608:21;:25;;-1:-1:-1;;;;;;284608:25:0;;;284344:425;;;284739:17;;;;284715:21;;:41;;284739:17;-1:-1:-1;;;;;284715:21:0;:41;:::i;:::-;284666:21;:91;;-1:-1:-1;;;;;;284666:91:0;-1:-1:-1;;;;;284666:91:0;;;;;;;;;;284344:425;284986:22;;;;:26;284982:372;;285042:12;;285078:22;;;;:49;;196541:5;;285078:49;:::i;:::-;285073:2;:54;285069:144;;;285155:42;;-1:-1:-1;;;285155:42:0;;;;;;;;;;;285069:144;285247:22;;;;285242:27;;:2;:27;:::i;:::-;285227:12;:42;285307:22;;;;;285289:53;;20432:25:1;;;-1:-1:-1;;;;;20493:32:1;;20488:2;20473:18;;20466:60;285289:53:0;;20405:18:1;285289:53:0;;;;;;;285014:340;284982:372;285411:23;;285366:128;;-1:-1:-1;;;285366:128:0;;-1:-1:-1;;;;;285366:30:0;;;;;:128;;285411:23;285449:10;;285474:8;;;;285366:128;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;281912:3590;;;;;281679:3823;;;;;;;:::o;250026:178::-;250135:9;250161:35;250188:1;250191;250194;250161:26;:35::i;249486:174::-;249548:45;;-1:-1:-1;;;249548:45:0;;249582:10;249548:45;;;3303:51:1;249548:15:0;-1:-1:-1;;;;;249548:33:0;;;;3276:18:1;;249548:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;249543:110;;249610:31;195673:10;249610:7;:31::i;:::-;249486:174::o;96740:957::-;96906:2;96900:4;96893:16;96964:6;96958:4;96951:20;-1:-1:-1;;;97024:4:0;97017:48;97424:4;97418;97412;97406;97403:1;97396:5;97389;97384:45;97317:16;97310:24;97306:1;97299:4;97293:11;97290:18;97287:48;97201:247;97173:408;;97496:10;97490:4;97483:24;97561:4;97555;97548:18;97173:408;97608:1;97602:4;97595:15;96740:957;;;:::o;247043:830::-;247170:17;:15;:17::i;:::-;247200:24;247217:6;247200:16;:24::i;:::-;247248:8;-1:-1:-1;;;;;247239:17:0;:5;-1:-1:-1;;;;;247239:17:0;;247235:84;;247280:27;;-1:-1:-1;;;247280:27:0;;;;;;;;;;;247235:84;-1:-1:-1;;;;;247362:23:0;;;247339:20;247362:23;;;:16;:23;;;;;;;247478:13;:25;;247526:4;247546:6;247379:5;247587:16;247379:5;9466:18;9460:4;9453:32;;;9358:14;9499:19;;;;9564:4;9548:21;;9542:28;;9295:293;247587:16;247618:12;247660:1;247645:12;:16;:31;;247671:5;247645:31;;;247664:4;247645:31;247478:209;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;247449:238;-1:-1:-1;247704:22:0;;247700:99;;247743:44;247761:18;247781:5;247743:17;:44::i;:::-;247159:714;;247043:830;;;:::o;12805:2235::-;12893:4;13048;13044:2;13040:13;13143:8;13137:4;13130:22;13189:20;13182:5;13179:31;13173:4;13166:45;13262:4;13256;13246:21;13305:13;13299:20;13419:1;13407:10;13403:18;13400:426;;;13537:10;13529:6;13526:22;13523:162;;;13585:10;13579:4;13572:24;13661:4;13655;13648:18;13523:162;13803:6;13791:10;13787:23;13772:13;13765:46;13400:426;;;13924:18;13917:5;13914:29;13908:4;13901:43;13997:4;13991;13981:21;14041:15;14035:22;14133:11;14125:6;14122:23;14119:149;;;14178:10;14172:4;14165:24;14248:4;14242;14235:18;14119:149;14379:6;14366:11;14362:24;14345:15;14338:49;;;14464:2;14458:4;14451:16;14518:4;14512;14502:21;14772:6;14756:13;14750:20;14746:33;14731:13;14724:56;;14850:6;14844:4;14837:20;14945:4;14939:11;14935:2;14931:20;14923:5;14919:2;14915:14;-1:-1:-1;;;;;;;;;;;14882:4:0;14876;14871:81;;-1:-1:-1;15028:4:0;12805:2235;;;;;:::o;132377:186::-;132511:1;132505:4;132498:15;132540:4;132534;132527:18;224431:634;224534:14;224561:17;:15;:17::i;:::-;224711:70;224737:43;224754:6;224762:17;:15;:17::i;224737:43::-;224728:52;;;224711:16;:70::i;:::-;224926:36;;-1:-1:-1;;;224926:36:0;;224956:4;224926:36;;;3303:51:1;224926:13:0;-1:-1:-1;;;;;224926:21:0;;;;3276:18:1;;224926:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;225004:53;225020:6;225028;225036:10;225048:8;225004:15;:53::i;285975:348::-;-1:-1:-1;;;;;286174:14:0;;286192:1;286174:14;;;:7;:14;;;;;;-1:-1:-1;;;;;286166:27:0;;286162:105;;286217:38;;-1:-1:-1;;;286217:38:0;;;;;;;;;;;286162:105;286279:36;286301:6;286309:5;286279:21;:36::i;:::-;285975:348;;:::o;246126:518::-;246234:24;246251:6;246234:16;:24::i;:::-;-1:-1:-1;;;;;246294:23:0;;246271:20;246294:23;;;:16;:23;;;;;;246332:21;;;246328:95;;;246370:41;195831:10;246370:7;:41::i;:::-;246435:13;-1:-1:-1;;;;;246435:44:0;;246502:4;246522:6;246543:5;246563:16;246573:5;9466:18;9460:4;9453:32;;;9358:14;9499:19;;;;9564:4;9548:21;;9542:28;;9295:293;246563:16;246594:12;246621:4;246435:201;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;246223:421;246126:518;;:::o;231703:331::-;-1:-1:-1;;;;;231872:23:0;;;;;;:16;:23;;;;;;:32;;231898:6;;231872:32;:::i;:::-;-1:-1:-1;;;;;231846:23:0;;;;;;:16;:23;;;;;:58;231940:22;;:31;;231965:6;;231940:31;:::i;:::-;231915:22;:56;231987:39;;;24234:25:1;;;232013:5:0;24290:2:1;24275:18;;24268:50;-1:-1:-1;;;;;24354:32:1;;24334:18;;;24327:60;;;;231987:39:0;;24222:2:1;24207:18;231987:39:0;;;;;;;;231703:331;;:::o;278941:1576::-;279055:7;279114:17;:15;:17::i;:::-;279200:14;279217:18;279229:5;279217:11;:18::i;:::-;279200:35;-1:-1:-1;279313:11:0;;:29;;279336:6;279313:29;;;279327:6;279313:29;279304:38;;279353:24;279370:6;279353:16;:24::i;:::-;279459:6;279450;:15;279446:84;;;279482:36;255960:10;279482:7;:36::i;:::-;279542:71;213528:6;279584:5;279599:4;279606:6;279542:32;:71::i;:::-;-1:-1:-1;;;;;279730:13:0;:32;;279785:4;279814:15;279823:6;279814;:15;:::i;:::-;279805:24;-1:-1:-1;279805:24:0;213528:6;240971:9;279730:177;;-1:-1:-1;;;;;;279730:177:0;;;;;;;-1:-1:-1;;;;;34503:32:1;;;279730:177:0;;;34485:51:1;34552:18;;;34545:34;;;;34615:32;;;34595:18;;;34588:60;34696:4;34684:17;34664:18;;;34657:45;34739:32;;;34718:19;;;34711:61;34457:19;;279730:177:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;280000:12:0;;-1:-1:-1;;;;;294490:16:0;;294085:17;294490:16;;;:7;:16;;;;;-1:-1:-1;;;;;;294412:40:0;;;294363:104;;294490:28;;-1:-1:-1;279918:128:0;;-1:-1:-1;293942:584:0;279918:128;280253:21;;-1:-1:-1;;;;;280253:21:0;:30;-1:-1:-1;280249:184:0;;;280300:21;:25;;-1:-1:-1;;;;;;280300:25:0;;;280249:184;;;280390:21;;:30;;280414:6;;-1:-1:-1;;;;;280390:21:0;:30;:::i;:::-;280358:21;:63;;-1:-1:-1;;;;;;280358:63:0;-1:-1:-1;;;;;280358:63:0;;;;;;;;;;280249:184;280450:35;;;32815:25:1;;;32871:2;32856:18;;32849:34;;;-1:-1:-1;;;;;32919:32:1;;;32899:18;;;32892:60;32988:32;;32983:2;32968:18;;32961:60;280450:35:0;;;;;;;32802:3:1;280450:35:0;;;-1:-1:-1;280503:6:0;;278941:1576;-1:-1:-1;;;278941:1576:0:o;144304:270::-;-1:-1:-1;;;;;144404:17:0;;;:11;:17;;;;;;;;;;;144422:57;;-1:-1:-1;;;144422:57:0;;;;;3303:51:1;;;;144404:17:0;:11;;144422:15;:51;;;;;;3276:18:1;;144422:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;144404:76;;;;;;;;;;;;;;-1:-1:-1;144404:76:0;;;-1:-1:-1;;;;;144404:86:0;;;;;;;;;;;;144385:182;;144524:31;;-1:-1:-1;;;144524:31:0;;;;;;;;;;;245524:280;245635:24;245652:6;245635:16;:24::i;:::-;9466:18;9460:4;9453:32;;;9358:14;9499:19;;;9564:4;9548:21;;9542:28;-1:-1:-1;;;;;245676:23:0;;;;;;:16;:23;;;;;;:32;;245702:6;;245676:32;:::i;:::-;:51;245672:125;;;245744:41;195831:10;245744:7;:41::i;286517:5263::-;286668:12;;286691:67;255676:3;286725:32;;;286691:67;286856:15;:35;;;286852:74;;286908:7;;286517:5263::o;286852:74::-;287158:21;;287209:12;;-1:-1:-1;;;;;286938:34:0;;;286983:60;255556:2;287011:31;;;286983:60;;255813:3;287087:33;;;;-1:-1:-1;;;;;287158:21:0;;286938:12;287255:129;286938:34;287158:21;286983:60;287357:16;287255:13;:129::i;:::-;287232:152;;287483:10;287464:15;:29;287460:1434;;287843:3;;287667:10;;-1:-1:-1;287667:10:0;;287692:22;;-1:-1:-1;;;;;287843:3:0;:22;287884:12;:10;:12::i;:::-;287915:30;287933:12;287915:15;:30;:::i;:::-;287843:117;;-1:-1:-1;;;;;;287843:117:0;;;;;;;;;;34957:25:1;;;;34998:18;;;34991:34;34930:18;;287843:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;287818:142;;-1:-1:-1;287818:142:0;-1:-1:-1;287818:142:0;;;288249:28;288267:10;288249:15;:28;:::i;:::-;288248:64;;;;:::i;:::-;288247:83;;;;:::i;:::-;288246:102;;;;:::i;:::-;288229:119;-1:-1:-1;288376:27:0;288229:119;288376:10;:27;:::i;:::-;288425:31;;;34957:25:1;;;35013:2;34998:18;;34991:34;;;288363:40:0;;-1:-1:-1;288425:31:0;;34930:18:1;288425:31:0;;;;;;;288718:164;288750:4;288773:30;288791:12;288773:15;:30;:::i;:::-;288822:10;288851:16;288718:13;:164::i;:::-;288702:180;;;;:::i;:::-;;;287495:1399;287460:1434;289093:11;;289047:19;;289069:41;;289079:12;;-1:-1:-1;;;289093:11:0;;;;745:3;289069:9;:41::i;:::-;289047:63;-1:-1:-1;289125:15:0;;289121:895;;289556:25;289584:163;289633:11;289663:13;9189:18;9183:25;;9026:200;289663:13;289721:11;289695:23;289706:12;289695:8;:23;:::i;:::-;:37;;;;:::i;:::-;289584:30;:163::i;:::-;289556:191;;289839:18;289860:15;-1:-1:-1;;;;;289860:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;289839:49;;289903:36;289909:10;289921:17;289903:5;:36::i;:::-;289142:874;;289121:895;290082:16;;290078:879;;290584:15;290503:57;290513:12;290527:15;290544;290503:9;:57::i;:::-;:96;;;;:::i;:::-;290468:131;-1:-1:-1;290721:30:0;290739:12;290721:15;:30;:::i;:::-;290689:21;:63;;-1:-1:-1;;;;;;290689:63:0;-1:-1:-1;;;;;290689:63:0;;;;;;;;;;290862:23;290873:12;290862:8;:23;:::i;:::-;290847:12;:38;290907;;;34957:25:1;;;35013:2;34998:18;;34991:34;;;290907:38:0;;34930:18:1;290907:38:0;;;;;;;290078:879;-1:-1:-1;;;;291423:16:0;291419:33;;;;291502:11;291483:17;291479:35;291390:147;291564:18;291560:40;;;;291365:254;-1:-1:-1;;;;;291113:32:0;;;;291321:315;291731:17;291724:38;-1:-1:-1;;286517:5263:0:o;277456:983::-;277576:24;277593:6;277576:16;:24::i;:::-;277611;277628:6;277611:16;:24::i;:::-;-1:-1:-1;;;;;277757:23:0;;277783:1;277757:23;;;:16;:23;;;;;;:27;277753:111;;277808:44;;-1:-1:-1;;;277808:44:0;;;;;;;;;;;277753:111;278012:14;278050:6;278029:18;278041:5;278029:11;:18::i;:::-;:27;;;;:::i;:::-;278149:12;;-1:-1:-1;;;;;294490:16:0;;294085:17;294490:16;;;:7;:16;;;;;-1:-1:-1;;;;;;294412:40:0;;;294363:104;;294490:28;;278012:44;-1:-1:-1;278238:21:0;;:30;;278262:6;;-1:-1:-1;;;;;278238:21:0;:30;:::i;:::-;278206:21;:63;;-1:-1:-1;;;;;;278206:63:0;-1:-1:-1;;;;;278206:63:0;;;;;;;;;;278329:55;213528:6;278367:8;278377:6;278329:28;:55::i;:::-;278402:29;;;23320:25:1;;;23376:2;23361:18;;23354:34;;;-1:-1:-1;;;;;23424:32:1;;23404:18;;;23397:60;278402:29:0;;;;;;;23308:2:1;278402:29:0;;;277565:874;277456:983;;;:::o;248853:358::-;248998:6;248988:205;;249038:10;249032:4;249025:24;249173:4;249167;249160:18;248988:205;248853:358;:::o;93479:1160::-;93665:4;93659:11;93731:6;93725:4;93718:20;93797:2;93791:4;93784:16;93863:4;93859:2;93855:13;93849:4;93842:27;-1:-1:-1;;;93920:4:0;93913:48;94332:4;94326;94320;94314;94311:1;94304:5;94297;94292:45;94225:16;94218:24;94214:1;94207:4;94201:11;94198:18;94195:48;94109:247;94081:412;;94404:10;94398:4;94391:24;94473:4;94467;94460:18;94081:412;94520:1;94514:4;94507:15;94577:4;94570:15;-1:-1:-1;;;;93479:1160:0:o;237901:1473::-;238125:4;238121:2;238117:13;238228:18;238221:5;238218:29;238212:4;238205:43;238301:4;238295;238285:21;238345:15;238339:22;238437:11;238429:6;238426:23;238423:149;;;238482:10;238476:4;238469:24;238552:4;238546;238539:18;238423:149;238683:6;238670:11;238666:24;238649:15;238642:49;;;238768:2;238762:4;238755:16;238822:4;238816;238806:21;239076:6;239060:13;239054:20;239050:33;239035:13;239028:56;;239154:6;239148:4;239141:20;239335:4;239329:11;239325:2;239321:20;239296:5;239292:2;239288:14;-1:-1:-1;;;;;;;;;;;239221:4:0;239198;239175:181;;237901:1473;;;:::o;249738:184::-;249805:50;;-1:-1:-1;;;249805:50:0;;249844:10;249805:50;;;3303:51:1;249805:15:0;-1:-1:-1;;;;;249805:38:0;;;;3276:18:1;;249805:50:0;3138:222:1;293081:508:0;255143:4;293258:14;:41;293254:110;;;293316:36;255960:10;293316:7;:36::i;:::-;293460:11;;;;293484:36;;;-1:-1:-1;;;293484:36:0;;;-1:-1:-1;;;;;293484:36:0;;;;;;;293538:43;;;293460:11;;;;;;35952:25:1;;;293569:11:0;;;;;;;36008:2:1;35993:18;;35986:47;293460:11:0;293538:43;;35925:18:1;293538:43:0;35779:260:1;228973:1392:0;229167:14;229194:17;:15;:17::i;:::-;229306:10;229319:17;:15;:17::i;:::-;229306:30;;229347:15;229365:116;229405:28;229422:6;229430:2;229405:16;:28::i;:::-;229396:37;;;229448:5;229468:2;229365:16;:116::i;:::-;229347:134;;229683:15;229679:145;;;229715:33;229730:5;229737:10;229715:14;:33::i;:::-;229679:145;;;229781:31;229798:5;229805:6;229781:16;:31::i;:::-;-1:-1:-1;;;;;230070:23:0;;;229891:26;230070:23;;;:16;:23;;;;;;;229920:220;;-1:-1:-1;;;229920:220:0;;229891:26;;229920:13;:44;;;;:220;;229987:4;;230007:6;;230028:5;;230048:7;;230108:21;;229920:220;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;229891:249;-1:-1:-1;230157:22:0;;230153:99;;230196:44;230214:18;230234:5;230196:17;:44::i;:::-;230296:61;230313:6;230321;230329:10;230341:8;230351:5;230296:16;:61::i;:::-;229183:1182;;;228973:1392;;;;;;;:::o;226834:1185::-;226999:14;227026:17;:15;:17::i;:::-;227138:10;227151:17;:15;:17::i;:::-;227138:30;;227179:15;227197:35;227214:6;227222:5;227229:2;227197:16;:35::i;:::-;227179:53;;227339:62;227356:5;227372:28;227389:6;227397:2;227372:16;:28::i;:::-;227363:37;;;227339:16;:62::i;:::-;-1:-1:-1;;;;;227648:23:0;;;227469:26;227648:23;;;:16;:23;;;;;;;227498:220;;-1:-1:-1;;;227498:220:0;;227469:26;;227498:13;:44;;;;:220;;227565:4;;227585:6;;227606:5;;227626:7;;227686:21;;227498:220;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;227469:249;-1:-1:-1;227735:22:0;;227731:99;;227774:44;227792:18;227812:5;227774:17;:44::i;:::-;227874:137;227905:6;227926;227947:10;227972:8;227995:5;227874:16;:137::i;:::-;227015:1004;;;226834:1185;;;;;;:::o;294869:581::-;295018:3;;:17;;;-1:-1:-1;;;295018:17:0;;;;295047:4;;-1:-1:-1;;;;;295018:3:0;;:15;;:17;;;;;;;;;;;;;;:3;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;295018:34:0;;295014:98;;295069:31;195673:10;295069:7;:31::i;:::-;295124:29;295150:2;295124:25;:29::i;:::-;255813:3;636:4;295416:25;;255676:3;295362:15;:36;;255556:2;295309:15;:35;;-1:-1:-1;;;;;295255:12:0;;:36;295254:91;:145;:188;295239:12;:203;;;;294869:581;:::o;225443:635::-;225543:14;225570:17;:15;:17::i;:::-;225600:24;225617:6;225600:16;:24::i;:::-;225762:36;;-1:-1:-1;;;225762:36:0;;225792:4;225762:36;;;3303:51:1;225762:13:0;-1:-1:-1;;;;;225762:21:0;;;;3276:18:1;;225762:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;225912:158;225951:39;225964:6;225972:17;:15;:17::i;225951:39::-;225942:48;;;226005:6;226026:10;226051:8;225912:15;:158::i;10991:1435::-;11061:4;11275:18;11269:4;11262:32;11321:8;11315:4;11308:22;11383:4;11377;11367:21;11427:15;11421:22;11519:11;11511:6;11508:23;11505:149;;;11564:10;11558:4;11551:24;11634:4;11628;11621:18;11505:149;11765:6;11752:11;11748:24;11731:15;11724:49;;;11850:2;11844:4;11837:16;11904:4;11898;11888:21;12158:6;12142:13;12136:20;12132:33;12117:13;12110:56;;12236:6;12230:4;12223:20;12325:4;12319:11;12315:2;12311:20;12301:8;-1:-1:-1;;;;;;;;;;;12268:4:0;12262;12257:75;-1:-1:-1;12414:4:0;10991:1435;;;;:::o;243383:299::-;243481:14;243508:19;243530:13;9189:18;9183:25;;9026:200;243530:13;243508:35;-1:-1:-1;243565:16:0;;:109;;243619:55;243650:6;243658:2;243662:11;243619:30;:55::i;248332:442::-;248458:15;248486:24;248503:6;248486:16;:24::i;:::-;-1:-1:-1;9466:18:0;9460:4;9453:32;;;9358:14;9499:19;;;9564:4;9548:21;;9542:28;248612:48;9542:28;248657:2;248612:16;:48::i;:::-;248603:6;:57;248599:131;;;248677:41;195831:10;248677:7;:41::i;:::-;248742:24;248759:6;248742:16;:24::i;234147:665::-;234414:20;234420:5;234427:6;234414:5;:20::i;:::-;234581:34;234608:6;234581:26;:34::i;:::-;234686:55;213528:6;234724:8;234734:6;234686:28;:55::i;:::-;234782:5;-1:-1:-1;;;;;234759:45:0;234772:8;-1:-1:-1;;;;;234759:45:0;234768:2;-1:-1:-1;;;;;234759:45:0;;234789:6;234797;234759:45;;;;;;34957:25:1;;;35013:2;34998:18;;34991:34;34945:2;34930:18;;34783:248;234759:45:0;;;;;;;;234147:665;;;;;:::o;236280:995::-;236601:138;;-1:-1:-1;;;236601:138:0;;236618:10;;236601:37;;:138;;236661:4;;236681:6;;236702:5;;236722:6;;236601:138;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;9466:18:0;9460:4;9453:32;;;9358:14;9499:19;;;9564:4;9548:21;;9542:28;236772:25;;-1:-1:-1;236791:6:0;;-1:-1:-1;236772:25:0;:::i;:::-;236756:12;:41;236752:109;;236821:28;;-1:-1:-1;;;236821:28:0;;;;;;;;;;;236752:109;-1:-1:-1;;;;;237102:23:0;;;236918:26;237102:23;;;:16;:23;;;;;;;236947:209;;-1:-1:-1;;;236947:209:0;;236918:26;;236947:13;:44;;;;:209;;237014:4;;237034:6;;237055:5;;237075:12;;236918:26;;236947:209;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;236918:238;-1:-1:-1;237173:22:0;;237169:99;;237212:44;237230:18;237250:5;237212:17;:44::i;:::-;236510:765;236280:995;;;;;:::o;241968:301::-;242070:14;242097:19;242119:13;9189:18;9183:25;;9026:200;242119:13;242097:35;-1:-1:-1;242154:16:0;;:107;;242208:53;242237:6;242245:11;242258:2;242208:28;:53::i;292078:703::-;292224:128;292282:6;-1:-1:-1;;;292224:31:0;:128::i;:::-;292205:222;;292379:36;255960:10;292379:7;:36::i;:::-;292534:3;;;-1:-1:-1;;;;;;292610:12:0;;-1:-1:-1;;;;;292610:12:0;;;;;;;;;292653:24;;;-1:-1:-1;;;292653:24:0;;;;292534:3;;;;;-1:-1:-1;;292653:22:0;;:24;;;;;;;;;;;;;;292610:12;292653:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;292688:13;:25;;;292731:42;;;-1:-1:-1;;;;;37878:32:1;;;37860:51;;37947:32;;37942:2;37927:18;;37920:60;37996:18;;;37989:34;;;292633:44:0;;-1:-1:-1;292731:42:0;;37848:2:1;37833:18;292731:42:0;;;;;;;;292124:657;;292078:703;:::o;77794:265::-;77887:12;77913;77927:23;77954:6;-1:-1:-1;;;;;77954:11:0;77973:1;77976:4;77954:27;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77912:69;;;;78009:42;78023:6;78031:7;78040:10;78009:13;:42::i;:::-;78002:49;77794:265;-1:-1:-1;;;;;77794:265:0:o;79674:263::-;79775:12;79801;79815:23;79842:6;-1:-1:-1;;;;;79842:19:0;79862:4;79842:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;295693:423;295872:12;;295967:21;;295750:14;;295872:12;295905:203;;-1:-1:-1;;;;;295905:203:0;;;-1:-1:-1;;;;;295967:21:0;295905:203;255556:2;296010:31;;;295905:203;;;255676:3;296064:32;;;295905:203;:13;:203::i;31289:3640::-;31912:9;;;-1:-1:-1;;31919:1:0;31916;31998:20;32128:14;;;32116:27;;32108:36;;;32232:285;;32279:1;32269:156;;32322:10;32316:4;32309:24;32397:4;32391;32384:18;32269:156;-1:-1:-1;32457:14:0;;;32493:5;;32232:285;32641:2;32638:1;32635:9;32625:152;;32682:10;32676:4;32669:24;32753:4;32747;32740:18;32625:152;33040:1;33037;33034;33027:15;33191:1;33187:9;;;33180:17;;33284:9;;;;;34625:13;;;34617:22;;;34649:9;;;;34645:17;;;34664:1;34641:25;34613:54;34702:14;;34698:22;34580:167;33665:1;33672;33668:9;;33661:17;;33951:11;;;33944:19;;33935:29;34025:11;;;34018:19;;34009:29;34100:11;;;34093:19;;34084:29;34175:11;;;34168:19;;34159:29;34250:11;;;34243:19;;34234:29;34837:11;;;34830:19;;;34821:29;34334:539;31289:3640;;;;;:::o;35217:474::-;35295:14;35331:19;35342:1;35345;35348;35331:10;:19::i;:::-;35322:28;;35445:1;35442;35439;35432:15;35429:244;;;35489:1;35477:14;;35509:149;;35563:10;35557:4;35550:24;35634:4;35628;35621:18;36376:518;36450:9;36677:1;36673;36669:6;36665:14;36662:1;36659:21;36656:1;36652:29;36645:37;36642:1;36638:45;36628:172;;36717:10;36711:4;36704:24;36780:4;36774;36767:18;36628:172;-1:-1:-1;36862:9:0;;36837:17;;;36830:25;36823:33;36858:17;;;36819:57;;36376:518::o;232711:754::-;232921:68;213528:6;232963:2;232975:4;232982:6;232921:32;:68::i;:::-;233134:31;233158:6;233134:23;:31::i;:::-;233331:23;233337:8;233347:6;233331:5;:23::i;:::-;233384:8;-1:-1:-1;;;;;233372:37:0;233380:2;-1:-1:-1;;;;;233372:37:0;;233394:6;233402;233372:37;;;;;;34957:25:1;;;35013:2;34998:18;;34991:34;34945:2;34930:18;;34783:248;233372:37:0;;;;;;;;233420;285975:348;230730:496;230839:24;230891:6;230866:22;;:31;;;;:::i;:::-;230908:70;;-1:-1:-1;;;230908:70:0;;230947:4;230908:70;;;37860:51:1;-1:-1:-1;;;;;37947:32:1;;;37927:18;;;37920:60;37996:18;;;37989:34;;;230839:58:0;;-1:-1:-1;230908:13:0;:30;;;;;;37833:18:1;;230908:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;231080:23:0;;;;;;:16;:23;;;;;;:32;;-1:-1:-1;231106:6:0;;231080:32;:::i;:::-;-1:-1:-1;;;;;231054:23:0;;;;;;:16;:23;;;;;;;;;:58;;;;231123:22;:41;;;231180:38;;24234:25:1;;;24275:18;;;24268:50;24334:18;;24327:60;231180:38:0;;24222:2:1;24207:18;231180:38:0;24038:355:1;296359:1050:0;296540:14;296645:1;296631:11;:15;:48;;;;;296669:10;296650:16;:29;296631:48;296627:775;;;297122:268;297166:10;297148:15;:28;:171;;297289:29;297302:16;297289:10;:29;:::i;:::-;297274:45;;:11;:45;:::i;:::-;297148:171;;;297215:34;297233:16;297215:15;:34;:::i;:::-;297200:50;;:11;:50;:::i;:::-;297338:15;636:4;297122:7;:268::i;21132:1196::-;21357:18;21351:25;21437:6;21418:17;21414:30;21536:17;21518:16;21515:39;21512:165;;;21587:10;21581:4;21574:24;21657:4;21651;21644:18;21512:165;21766:16;21746:18;21739:44;;;21871:18;21865:4;21858:32;21917:2;21911:4;21904:16;21971:4;21965;21955:21;22089:6;22073:13;22067:20;22063:33;22048:13;22041:56;;22167:6;22161:4;22154:20;22249:4;22243:11;22239:2;22235:20;22232:1;-1:-1:-1;;;;;;;;;;;22199:4:0;22193;22188:68;285975:348;;:::o;297735:186::-;297830:6;297815:12;:10;:12::i;:::-;:21;297811:103;;;297860:42;;-1:-1:-1;;;297860:42:0;;;;;;;;;;;240637:178;240718:10;-1:-1:-1;;;;;240718:19:0;;;240714:94;;240754:42;240770:5;240777:10;240789:6;240754:15;:42::i;239717:749::-;239790:10;-1:-1:-1;;;;;239812:13:0;239790:36;;239786:100;;239843:31;195673:10;239843:7;:31::i;:::-;239930:4;196541:5;240008:68;213528:6;240050:2;240054:13;240069:6;240008:32;:68::i;:::-;240274:6;240294:25;240233:14;240274:6;240294:5;:25::i;:::-;240330:12;:21;;;240369:39;;;34957:25:1;;;35013:2;34998:18;;34991:34;;;240389:1:0;;-1:-1:-1;;;;;240369:39:0;;;;;34930:18:1;240369:39:0;34783:248:1;22950:1142:0;23222:18;23216:4;23209:32;23268:4;23262;23255:18;23326:4;23320;23310:21;23370:15;23364:22;23462:11;23454:6;23451:23;23448:149;;;23507:10;23501:4;23494:24;23577:4;23571;23564:18;23448:149;23691:24;;;23667:49;;23828:18;23822:25;;23818:38;;;23791:66;;-1:-1:-1;23914:20:0;;;-1:-1:-1;;;;;23992:22:0;;-1:-1:-1;;;;;;;;;;;23959:4:0;-1:-1:-1;23948:70:0;285975:348;;:::o;244795:194::-;244975:6;244960:12;;:21;;;;:::i;:::-;244945:12;:36;-1:-1:-1;244795:194:0:o;105671:336::-;105783:4;105905:23;105920:7;105905:14;:23::i;:::-;:94;;;;;105945:54;105978:7;105987:11;105945:32;:54::i;80151:513::-;80286:12;80311:36;80327:7;80336:10;80311:15;:36::i;:::-;80509:17;;:22;:49;;;;-1:-1:-1;;;;;;80535:18:0;;;:23;80509:49;80505:122;;;80582:33;;-1:-1:-1;;;80582:33:0;;;;;;;;;;;80505:122;-1:-1:-1;80646:10:0;80151:513;-1:-1:-1;;80151:513:0:o;244476:187::-;244649:6;244634:12;;:21;;;;:::i;250309:174::-;250416:9;250442:33;250467:1;250470;250473;250442:24;:33::i;26666:967::-;26911:7;26905:4;26898:21;26946:20;26940:4;26933:34;26994:5;26988:4;26981:19;27051:4;27045;27035:21;27094:13;27088:20;27208:1;27196:10;27192:18;27189:426;;;27326:10;27318:6;27315:22;27312:162;;;27374:10;27368:4;27361:24;27450:4;27444;27437:18;27312:162;27576:23;;;;27554:46;;-1:-1:-1;;26666:967:0:o;104963:482::-;105027:4;105238:117;105289:7;-1:-1:-1;;;105238:32:0;:117::i;:::-;:199;;;;-1:-1:-1;105373:64:0;105406:7;-1:-1:-1;;;;;;105373:32:0;:64::i;:::-;105372:65;105218:219;104963:482;-1:-1:-1;;104963:482:0:o;106852:826::-;107050:93;;-1:-1:-1;;;;;;38502:33:1;;107050:93:0;;;38484:52:1;106979:4:0;;;;38457:18:1;;107050:93:0;;;-1:-1:-1;;107050:93:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;107050:93:0;-1:-1:-1;;;107050:93:0;;;107427:20;;107050:93;;-1:-1:-1;;;;;;;107050:93:0;;-1:-1:-1;;107358:7:0;107334:5;107305:203;107294:214;;107536:16;107522:30;;107587:4;107581:11;107566:26;;107622:7;:29;;;;;107647:4;107633:10;:18;;107622:29;:48;;;;;107669:1;107655:11;:15;107622:48;107615:55;106852:826;-1:-1:-1;;;;;;;106852:826:0:o;80840:425::-;80959:7;80954:304;;80987:10;:17;81008:1;80987:22;80983:103;;81037:33;;-1:-1:-1;;;81037:33:0;;;;;;;;;;;80983:103;81220:10;81214:17;81201:10;81197:2;81193:19;81186:46;35796:476;35868:9;36095:1;36091;36087:6;36083:14;36080:1;36077:21;36074:1;36070:29;36063:37;36060:1;36056:45;36046:172;;36135:10;36129:4;36122:24;36198:4;36192;36185:18;36046:172;-1:-1:-1;36241:9:0;;36237:17;;35796:476::o;196:286:1:-;254:6;307:2;295:9;286:7;282:23;278:32;275:52;;;323:1;320;313:12;275:52;349:23;;-1:-1:-1;;;;;;401:32:1;;391:43;;381:71;;448:1;445;438:12;679:289;721:3;759:5;753:12;786:6;781:3;774:19;842:6;835:4;828:5;824:16;817:4;812:3;808:14;802:47;894:1;887:4;878:6;873:3;869:16;865:27;858:38;957:4;950:2;946:7;941:2;933:6;929:15;925:29;920:3;916:39;912:50;905:57;;;679:289;;;;:::o;973:220::-;1122:2;1111:9;1104:21;1085:4;1142:45;1183:2;1172:9;1168:18;1160:6;1142:45;:::i;1198:226::-;1257:6;1310:2;1298:9;1289:7;1285:23;1281:32;1278:52;;;1326:1;1323;1316:12;1278:52;-1:-1:-1;1371:23:1;;1198:226;-1:-1:-1;1198:226:1:o;1429:131::-;-1:-1:-1;;;;;1504:31:1;;1494:42;;1484:70;;1550:1;1547;1540:12;1565:367;1633:6;1641;1694:2;1682:9;1673:7;1669:23;1665:32;1662:52;;;1710:1;1707;1700:12;1662:52;1749:9;1736:23;1768:31;1793:5;1768:31;:::i;:::-;1818:5;1896:2;1881:18;;;;1868:32;;-1:-1:-1;;;1565:367:1:o;1937:::-;2000:8;2010:6;2064:3;2057:4;2049:6;2045:17;2041:27;2031:55;;2082:1;2079;2072:12;2031:55;-1:-1:-1;2105:20:1;;-1:-1:-1;;;;;2137:30:1;;2134:50;;;2180:1;2177;2170:12;2134:50;2217:4;2209:6;2205:17;2193:29;;2277:3;2270:4;2260:6;2257:1;2253:14;2245:6;2241:27;2237:38;2234:47;2231:67;;;2294:1;2291;2284:12;2231:67;1937:367;;;;;:::o;2309:572::-;2404:6;2412;2420;2473:2;2461:9;2452:7;2448:23;2444:32;2441:52;;;2489:1;2486;2479:12;2441:52;2529:9;2516:23;-1:-1:-1;;;;;2554:6:1;2551:30;2548:50;;;2594:1;2591;2584:12;2548:50;2633:70;2695:7;2686:6;2675:9;2671:22;2633:70;:::i;:::-;2722:8;;-1:-1:-1;2607:96:1;-1:-1:-1;;2807:2:1;2792:18;;2779:32;2820:31;2779:32;2820:31;:::i;:::-;2870:5;2860:15;;;2309:572;;;;;:::o;2886:247::-;2945:6;2998:2;2986:9;2977:7;2973:23;2969:32;2966:52;;;3014:1;3011;3004:12;2966:52;3053:9;3040:23;3072:31;3097:5;3072:31;:::i;4015:508::-;4092:6;4100;4108;4161:2;4149:9;4140:7;4136:23;4132:32;4129:52;;;4177:1;4174;4167:12;4129:52;4216:9;4203:23;4235:31;4260:5;4235:31;:::i;:::-;4285:5;-1:-1:-1;4342:2:1;4327:18;;4314:32;4355:33;4314:32;4355:33;:::i;:::-;4015:508;;4407:7;;-1:-1:-1;;;4487:2:1;4472:18;;;;4459:32;;4015:508::o;4528:367::-;4596:6;4604;4657:2;4645:9;4636:7;4632:23;4628:32;4625:52;;;4673:1;4670;4663:12;4625:52;4718:23;;;-1:-1:-1;4817:2:1;4802:18;;4789:32;4830:33;4789:32;4830:33;:::i;:::-;4882:7;4872:17;;;4528:367;;;;;:::o;5271:903::-;5402:6;5410;5418;5426;5434;5487:2;5475:9;5466:7;5462:23;5458:32;5455:52;;;5503:1;5500;5493:12;5455:52;5543:9;5530:23;-1:-1:-1;;;;;5568:6:1;5565:30;5562:50;;;5608:1;5605;5598:12;5562:50;5647:70;5709:7;5700:6;5689:9;5685:22;5647:70;:::i;:::-;5736:8;;-1:-1:-1;5621:96:1;-1:-1:-1;;5824:2:1;5809:18;;5796:32;-1:-1:-1;;;;;5840:32:1;;5837:52;;;5885:1;5882;5875:12;5837:52;5924:72;5988:7;5977:8;5966:9;5962:24;5924:72;:::i;:::-;6015:8;;-1:-1:-1;5898:98:1;-1:-1:-1;;6100:2:1;6085:18;;6072:32;6113:31;6072:32;6113:31;:::i;:::-;6163:5;6153:15;;;5271:903;;;;;;;;:::o;6618:700::-;6697:6;6705;6713;6766:2;6754:9;6745:7;6741:23;6737:32;6734:52;;;6782:1;6779;6772:12;6734:52;6827:23;;;-1:-1:-1;6925:2:1;6910:18;;6897:32;-1:-1:-1;;;;;6941:30:1;;6938:50;;;6984:1;6981;6974:12;6938:50;7007:22;;7060:4;7052:13;;7048:27;-1:-1:-1;7038:55:1;;7089:1;7086;7079:12;7038:55;7129:2;7116:16;-1:-1:-1;;;;;7147:6:1;7144:30;7141:50;;;7187:1;7184;7177:12;7141:50;7232:7;7227:2;7218:6;7214:2;7210:15;7206:24;7203:37;7200:57;;;7253:1;7250;7243:12;7200:57;6618:700;;7284:2;7276:11;;;;;-1:-1:-1;7306:6:1;;-1:-1:-1;;;6618:700:1:o;7323:903::-;7454:6;7462;7470;7478;7486;7539:2;7527:9;7518:7;7514:23;7510:32;7507:52;;;7555:1;7552;7545:12;7507:52;7595:9;7582:23;-1:-1:-1;;;;;7620:6:1;7617:30;7614:50;;;7660:1;7657;7650:12;7614:50;7699:70;7761:7;7752:6;7741:9;7737:22;7699:70;:::i;:::-;7788:8;;-1:-1:-1;7673:96:1;-1:-1:-1;;7873:2:1;7858:18;;7845:32;7886:31;7845:32;7886:31;:::i;:::-;7936:5;-1:-1:-1;7994:2:1;7979:18;;7966:32;-1:-1:-1;;;;;8010:32:1;;8007:52;;;8055:1;8052;8045:12;8007:52;8094:72;8158:7;8147:8;8136:9;8132:24;8094:72;:::i;:::-;7323:903;;;;-1:-1:-1;7323:903:1;;-1:-1:-1;8185:8:1;;8068:98;7323:903;-1:-1:-1;;;7323:903:1:o;8231:508::-;8308:6;8316;8324;8377:2;8365:9;8356:7;8352:23;8348:32;8345:52;;;8393:1;8390;8383:12;8345:52;8438:23;;;-1:-1:-1;8537:2:1;8522:18;;8509:32;8550:33;8509:32;8550:33;:::i;:::-;8602:7;-1:-1:-1;8661:2:1;8646:18;;8633:32;8674:33;8633:32;8674:33;:::i;8744:388::-;8812:6;8820;8873:2;8861:9;8852:7;8848:23;8844:32;8841:52;;;8889:1;8886;8879:12;8841:52;8928:9;8915:23;8947:31;8972:5;8947:31;:::i;:::-;8997:5;-1:-1:-1;9054:2:1;9039:18;;9026:32;9067:33;9026:32;9067:33;:::i;9741:127::-;9802:10;9797:3;9793:20;9790:1;9783:31;9833:4;9830:1;9823:15;9857:4;9854:1;9847:15;9873:253;9945:2;9939:9;9987:4;9975:17;;-1:-1:-1;;;;;10007:34:1;;10043:22;;;10004:62;10001:88;;;10069:18;;:::i;:::-;10105:2;10098:22;9873:253;:::o;10131:::-;10203:2;10197:9;10245:4;10233:17;;-1:-1:-1;;;;;10265:34:1;;10301:22;;;10262:62;10259:88;;;10327:18;;:::i;10389:275::-;10460:2;10454:9;10525:2;10506:13;;-1:-1:-1;;10502:27:1;10490:40;;-1:-1:-1;;;;;10545:34:1;;10581:22;;;10542:62;10539:88;;;10607:18;;:::i;:::-;10643:2;10636:22;10389:275;;-1:-1:-1;10389:275:1:o;10669:153::-;10756:20;;10785:31;10756:20;10785:31;:::i;10827:558::-;10869:5;10922:3;10915:4;10907:6;10903:17;10899:27;10889:55;;10940:1;10937;10930:12;10889:55;10980:6;10967:20;-1:-1:-1;;;;;11002:6:1;10999:30;10996:56;;;11032:18;;:::i;:::-;11076:59;11123:2;11100:17;;-1:-1:-1;;11096:31:1;11129:4;11092:42;11076:59;:::i;:::-;11160:6;11151:7;11144:23;11214:3;11207:4;11198:6;11190;11186:19;11182:30;11179:39;11176:59;;;11231:1;11228;11221:12;11176:59;11296:6;11289:4;11281:6;11277:17;11270:4;11261:7;11257:18;11244:59;11352:1;11323:20;;;11345:4;11319:31;11312:42;;;;11327:7;10827:558;-1:-1:-1;;;10827:558:1:o;11390:993::-;11441:5;11489:4;11477:9;11472:3;11468:19;11464:30;11461:50;;;11507:1;11504;11497:12;11461:50;11529:22;;:::i;:::-;11520:31;;11588:9;11575:23;11607:33;11632:7;11607:33;:::i;:::-;11649:22;;11744:2;11729:18;;;11716:32;11764:14;;;11757:31;11840:2;11825:18;;11812:32;11853:33;11812:32;11853:33;:::i;:::-;11913:2;11902:14;;11895:31;11978:2;11963:18;;11950:32;11991:33;11950:32;11991:33;:::i;:::-;12051:2;12040:14;;12033:31;12137:3;12122:19;;;12109:33;12158:15;;;12151:32;12234:3;12219:19;;12206:33;-1:-1:-1;;;;;12251:30:1;;12248:50;;;12294:1;12291;12284:12;12248:50;12331:45;12372:3;12363:6;12352:9;12348:22;12331:45;:::i;:::-;12325:3;12318:5;12314:15;12307:70;;11390:993;;;;:::o;12388:1465::-;12497:6;12505;12513;12566:2;12554:9;12545:7;12541:23;12537:32;12534:52;;;12582:1;12579;12572:12;12534:52;12627:23;;;-1:-1:-1;12726:2:1;12711:18;;12698:32;12739:33;12698:32;12739:33;:::i;:::-;12791:7;-1:-1:-1;12849:2:1;12834:18;;12821:32;-1:-1:-1;;;;;12865:30:1;;12862:50;;;12908:1;12905;12898:12;12862:50;12931:22;;12987:4;12969:16;;;12965:27;12962:47;;;13005:1;13002;12995:12;12962:47;13033:22;;:::i;:::-;13080:41;13118:2;13080:41;:::i;:::-;13064:58;;13188:2;13180:11;;;13167:25;13208:16;;;13201:33;13268:50;13314:2;13306:11;;13268:50;:::i;:::-;13263:2;13250:16;;13243:76;13385:2;13377:11;;;13364:25;13405:16;;;13398:33;13477:3;13469:12;;13456:26;-1:-1:-1;;;;;13494:32:1;;13491:52;;;13539:1;13536;13529:12;13491:52;13578:50;13620:7;13609:8;13605:2;13601:17;13578:50;:::i;:::-;13572:3;13563:7;13559:17;13552:77;;13675:3;13671:2;13667:12;13654:26;-1:-1:-1;;;;;13695:8:1;13692:32;13689:52;;;13737:1;13734;13727:12;13689:52;13776:44;13812:7;13801:8;13797:2;13793:17;13776:44;:::i;:::-;13770:3;13761:7;13757:17;13750:71;;13840:7;13830:17;;;;12388:1465;;;;;:::o;14283:187::-;14347:4;-1:-1:-1;;;;;14372:6:1;14369:30;14366:56;;;14402:18;;:::i;:::-;-1:-1:-1;14447:1:1;14443:14;14459:4;14439:25;;14283:187::o;14475:841::-;14533:5;14586:3;14579:4;14571:6;14567:17;14563:27;14553:55;;14604:1;14601;14594:12;14553:55;14644:6;14631:20;14671:68;14687:51;14731:6;14687:51;:::i;:::-;14671:68;:::i;:::-;14763:3;14787:6;14782:3;14775:19;14819:4;14814:3;14810:14;14803:21;;14880:4;14870:6;14867:1;14863:14;14855:6;14851:27;14847:38;14833:52;;14908:3;14900:6;14897:15;14894:35;;;14925:1;14922;14915:12;14894:35;14961:4;14953:6;14949:17;14975:310;14991:6;14986:3;14983:15;14975:310;;;15079:3;15066:17;-1:-1:-1;;;;;15102:11:1;15099:35;15096:55;;;15147:1;15144;15137:12;15096:55;15176:64;15236:3;15229:4;15215:11;15207:6;15203:24;15199:35;15176:64;:::i;:::-;15164:77;;-1:-1:-1;15270:4:1;15261:14;;;;15008;14975:310;;;-1:-1:-1;15303:7:1;14475:841;-1:-1:-1;;;;;14475:841:1:o;15321:1477::-;15432:6;15440;15448;15501:2;15489:9;15480:7;15476:23;15472:32;15469:52;;;15517:1;15514;15507:12;15469:52;15562:23;;;-1:-1:-1;15661:2:1;15646:18;;15633:32;15674:33;15633:32;15674:33;:::i;:::-;15726:7;-1:-1:-1;15784:2:1;15769:18;;15756:32;-1:-1:-1;;;;;15800:30:1;;15797:50;;;15843:1;15840;15833:12;15797:50;15866:22;;15922:4;15904:16;;;15900:27;15897:47;;;15940:1;15937;15930:12;15897:47;15968:22;;:::i;:::-;16015:41;16053:2;16015:41;:::i;:::-;15999:58;;16123:2;16115:11;;;16102:25;16143:16;;;16136:33;16203:50;16249:2;16241:11;;16203:50;:::i;:::-;16198:2;16185:16;;16178:76;16320:2;16312:11;;;16299:25;16340:16;;;16333:33;16412:3;16404:12;;16391:26;-1:-1:-1;;;;;16429:32:1;;16426:52;;;16474:1;16471;16464:12;16426:52;16513:60;16565:7;16554:8;16550:2;16546:17;16513:60;:::i;16803:118::-;16889:5;16882:13;16875:21;16868:5;16865:32;16855:60;;16911:1;16908;16901:12;16926:382;16991:6;16999;17052:2;17040:9;17031:7;17027:23;17023:32;17020:52;;;17068:1;17065;17058:12;17020:52;17107:9;17094:23;17126:31;17151:5;17126:31;:::i;:::-;17176:5;-1:-1:-1;17233:2:1;17218:18;;17205:32;17246:30;17205:32;17246:30;:::i;17313:1037::-;17424:6;17432;17440;17448;17456;17464;17472;17525:3;17513:9;17504:7;17500:23;17496:33;17493:53;;;17542:1;17539;17532:12;17493:53;17581:9;17568:23;17600:31;17625:5;17600:31;:::i;:::-;17650:5;-1:-1:-1;17707:2:1;17692:18;;17679:32;17720:33;17679:32;17720:33;:::i;:::-;17772:7;-1:-1:-1;17852:2:1;17837:18;;17824:32;;-1:-1:-1;17955:2:1;17940:18;;17927:32;;-1:-1:-1;18037:3:1;18022:19;;18009:33;18086:4;18073:18;;18061:31;;18051:59;;18106:1;18103;18096:12;18051:59;17313:1037;;;;-1:-1:-1;17313:1037:1;;;;18129:7;18209:3;18194:19;;18181:33;;-1:-1:-1;18313:3:1;18298:19;;;18285:33;;17313:1037;-1:-1:-1;;17313:1037:1:o;18355:472::-;18476:6;18484;18537:2;18525:9;18516:7;18512:23;18508:32;18505:52;;;18553:1;18550;18543:12;18505:52;18593:9;18580:23;-1:-1:-1;;;;;18618:6:1;18615:30;18612:50;;;18658:1;18655;18648:12;18612:50;18697:70;18759:7;18750:6;18739:9;18735:22;18697:70;:::i;:::-;18786:8;;18671:96;;-1:-1:-1;18355:472:1;-1:-1:-1;;;;18355:472:1:o;18832:780::-;18992:4;19040:2;19029:9;19025:18;19070:2;19059:9;19052:21;19093:6;19128;19122:13;19159:6;19151;19144:22;19197:2;19186:9;19182:18;19175:25;;19259:2;19249:6;19246:1;19242:14;19231:9;19227:30;19223:39;19209:53;;19297:2;19289:6;19285:15;19318:1;19328:255;19342:6;19339:1;19336:13;19328:255;;;19435:2;19431:7;19419:9;19411:6;19407:22;19403:36;19398:3;19391:49;19463:40;19496:6;19487;19481:13;19463:40;:::i;:::-;19453:50;-1:-1:-1;19538:2:1;19561:12;;;;19526:15;;;;;19364:1;19357:9;19328:255;;;-1:-1:-1;19600:6:1;;18832:780;-1:-1:-1;;;;;;18832:780:1:o;19617:380::-;19696:1;19692:12;;;;19739;;;19760:61;;19814:4;19806:6;19802:17;19792:27;;19760:61;19867:2;19859:6;19856:14;19836:18;19833:38;19830:161;;19913:10;19908:3;19904:20;19901:1;19894:31;19948:4;19945:1;19938:15;19976:4;19973:1;19966:15;19830:161;;19617:380;;;:::o;20002:251::-;20072:6;20125:2;20113:9;20104:7;20100:23;20096:32;20093:52;;;20141:1;20138;20131:12;20093:52;20173:9;20167:16;20192:31;20217:5;20192:31;:::i;20537:245::-;20604:6;20657:2;20645:9;20636:7;20632:23;20628:32;20625:52;;;20673:1;20670;20663:12;20625:52;20705:9;20699:16;20724:28;20746:5;20724:28;:::i;20787:127::-;20848:10;20843:3;20839:20;20836:1;20829:31;20879:4;20876:1;20869:15;20903:4;20900:1;20893:15;21072:501;21151:6;21159;21167;21220:2;21208:9;21199:7;21195:23;21191:32;21188:52;;;21236:1;21233;21226:12;21188:52;21268:9;21262:16;21287:28;21309:5;21287:28;:::i;:::-;21384:2;21369:18;;21363:25;21334:5;;-1:-1:-1;21397:30:1;21363:25;21397:30;:::i;:::-;21498:2;21483:18;;21477:25;21446:7;;-1:-1:-1;21511:30:1;21477:25;21511:30;:::i;21578:125::-;21643:9;;;21664:10;;;21661:36;;;21677:18;;:::i;22156:230::-;22226:6;22279:2;22267:9;22258:7;22254:23;22250:32;22247:52;;;22295:1;22292;22285:12;22247:52;-1:-1:-1;22340:16:1;;22156:230;-1:-1:-1;22156:230:1:o;22391:533::-;22604:6;22593:9;22586:25;22647:6;22642:2;22631:9;22627:18;22620:34;22690:2;22685;22674:9;22670:18;22663:30;22729:6;22724:2;22713:9;22709:18;22702:34;22787:6;22779;22773:3;22762:9;22758:19;22745:49;22844:1;22814:22;;;22838:3;22810:32;;;22803:43;;;;22907:2;22886:15;;;-1:-1:-1;;22882:29:1;22867:45;22863:55;;22391:533;-1:-1:-1;;;22391:533:1:o;23773:127::-;23834:10;23829:3;23825:20;23822:1;23815:31;23865:4;23862:1;23855:15;23889:4;23886:1;23879:15;23905:128;23972:9;;;23993:11;;;23990:37;;;24007:18;;:::i;24774:550::-;24855:12;;-1:-1:-1;;;;;24851:38:1;;;24839:51;;24939:4;24928:16;;;24922:23;24906:14;;;24899:47;24999:4;24988:16;;;24982:23;24978:49;;24962:14;;;24955:73;25081:4;25070:16;;;25064:23;25060:49;;;25044:14;;;25037:73;25159:4;25148:16;;;25142:23;25126:14;;;25119:47;24877:3;25201:16;;;25195:23;25250:4;25234:14;;;25227:28;;;-1:-1:-1;;25271:47:1;;25303:14;;25195:23;25271:47;:::i;25329:1113::-;25635:1;25631;25626:3;25622:11;25618:19;25610:6;25606:32;25595:9;25588:51;25675:6;25670:2;25659:9;25655:18;25648:34;25747:1;25743;25738:3;25734:11;25730:19;25722:6;25718:32;25713:2;25702:9;25698:18;25691:60;25787:3;25782:2;25771:9;25767:18;25760:31;25864:1;25860;25855:3;25851:11;25847:19;25838:6;25832:13;25828:39;25822:3;25811:9;25807:19;25800:68;25923:2;25915:6;25911:15;25905:22;25899:3;25888:9;25884:19;25877:51;26011:1;26007;26002:3;25998:11;25994:19;25988:2;25980:6;25976:15;25970:22;25966:48;25959:4;25948:9;25944:20;25937:78;26070:2;26062:6;26058:15;26052:22;26046:3;26035:9;26031:19;26024:51;25569:4;26122:3;26114:6;26110:16;26104:23;26164:4;26158:3;26147:9;26143:19;26136:33;26192:57;26244:3;26233:9;26229:19;26215:12;26192:57;:::i;:::-;26178:71;;26298:3;26290:6;26286:16;26280:23;26372:3;26368:8;26356:9;26348:6;26344:22;26340:37;26334:3;26323:9;26319:19;26312:66;26395:41;26429:6;26413:14;26395:41;:::i;:::-;26387:49;25329:1113;-1:-1:-1;;;;;;;;25329:1113:1:o;27192:332::-;27293:4;27351:11;27338:25;27445:2;27441:7;27430:8;27414:14;27410:29;27406:43;27386:18;27382:68;27372:96;;27464:1;27461;27454:12;27372:96;27485:33;;;;;27192:332;-1:-1:-1;;27192:332:1:o;27529:728::-;27647:9;27706:4;27698:5;27682:14;27678:26;27674:37;27671:57;;;27724:1;27721;27714:12;27671:57;27752:22;;:::i;:::-;27811:5;27798:19;27826:33;27851:7;27826:33;:::i;:::-;27868:24;;27940:2;27929:14;;27916:28;27953:30;27916:28;27953:30;:::i;:::-;28012:2;27999:16;;27992:33;28072:2;28061:14;;28048:28;-1:-1:-1;;;;;28088:30:1;;28085:50;;;28131:1;28128;28121:12;28085:50;28169:52;28206:14;28197:6;28190:5;28186:18;28169:52;:::i;:::-;28164:2;28151:16;;28144:78;-1:-1:-1;28155:7:1;27529:728;-1:-1:-1;;27529:728:1:o;28262:412::-;-1:-1:-1;;;;;28465:32:1;;;28447:51;;28534:32;;28529:2;28514:18;;28507:60;28603:2;28598;28583:18;;28576:30;;;-1:-1:-1;;28623:45:1;;28649:18;;28641:6;28623:45;:::i;28679:420::-;28732:3;28770:5;28764:12;28797:6;28792:3;28785:19;28829:4;28824:3;28820:14;28813:21;;28868:4;28861:5;28857:16;28891:1;28901:173;28915:6;28912:1;28909:13;28901:173;;;28976:13;;28964:26;;29019:4;29010:14;;;;29047:17;;;;28937:1;28930:9;28901:173;;;-1:-1:-1;29090:3:1;;28679:420;-1:-1:-1;;;;28679:420:1:o;29104:505::-;29204:6;29199:3;29192:19;29236:4;29231:3;29227:14;29220:21;;29174:3;29264:5;29287:1;29297:287;29311:6;29308:1;29305:13;29297:287;;;29388:6;29375:20;29408:33;29433:7;29408:33;:::i;:::-;-1:-1:-1;;;;;29466:33:1;29454:46;;29529:4;29520:14;;;;29557:17;;;;;29496:1;29326:9;29297:287;;29614:1154;29991:3;29980:9;29973:22;29954:4;30018:57;30070:3;30059:9;30055:19;30047:6;30018:57;:::i;:::-;-1:-1:-1;;;;;30111:32:1;;30106:2;30091:18;;30084:60;30180:22;;;30175:2;30160:18;;30153:50;30220:61;30184:6;30266;30258;30220:61;:::i;:::-;30212:69;;;30353:1;30349;30344:3;30340:11;30336:19;30327:6;30321:13;30317:39;30312:2;30301:9;30297:18;30290:67;30439:1;30435;30430:3;30426:11;30422:19;30416:2;30408:6;30404:15;30398:22;30394:48;30388:3;30377:9;30373:19;30366:77;30498:2;30490:6;30486:15;30480:22;30474:3;30463:9;30459:19;30452:51;30572:2;30564:6;30560:15;30554:22;30547:30;30540:38;30534:3;30523:9;30519:19;30512:67;30634:3;30626:6;30622:16;30616:23;30610:3;30599:9;30595:19;30588:52;30695:3;30687:6;30683:16;30677:23;30671:3;30660:9;30656:19;30649:52;30756:3;30748:6;30744:16;30738:23;30732:3;30721:9;30717:19;30710:52;29614:1154;;;;;;;;:::o;30773:724::-;30838:5;30891:3;30884:4;30876:6;30872:17;30868:27;30858:55;;30909:1;30906;30899:12;30858:55;30942:6;30936:13;30969:68;30985:51;31029:6;30985:51;:::i;30969:68::-;31061:3;31085:6;31080:3;31073:19;31117:4;31112:3;31108:14;31101:21;;31178:4;31168:6;31165:1;31161:14;31153:6;31149:27;31145:38;31131:52;;31206:3;31198:6;31195:15;31192:35;;;31223:1;31220;31213:12;31192:35;31259:4;31251:6;31247:17;31273:193;31289:6;31284:3;31281:15;31273:193;;;31381:10;;31404:18;;31451:4;31442:14;;;;31306;31273:193;;31502:1077;31633:6;31641;31694:2;31682:9;31673:7;31669:23;31665:32;31662:52;;;31710:1;31707;31700:12;31662:52;31743:9;31737:16;-1:-1:-1;;;;;31768:6:1;31765:30;31762:50;;;31808:1;31805;31798:12;31762:50;31831:22;;31887:4;31869:16;;;31865:27;31862:47;;;31905:1;31902;31895:12;31862:47;31931:22;;:::i;:::-;31984:2;31978:9;-1:-1:-1;;;;;32002:8:1;31999:32;31996:52;;;32044:1;32041;32034:12;31996:52;32071:67;32130:7;32119:8;32115:2;32111:17;32071:67;:::i;:::-;32057:82;;-1:-1:-1;32198:2:1;32190:11;;;32184:18;32218:14;;;32211:31;32301:2;32293:11;;;32287:18;32321:14;;;32314:31;;;;32400:18;;;32394:25;32064:5;;-1:-1:-1;;;;;;32431:32:1;;32428:52;;;32476:1;32473;32466:12;32428:52;32499:74;32565:7;32554:8;32543:9;32539:24;32499:74;:::i;:::-;32489:84;;;31502:1077;;;;;:::o;33032:589::-;33327:2;33316:9;33309:21;33290:4;33353:56;33405:2;33394:9;33390:18;33382:6;33353:56;:::i;:::-;-1:-1:-1;;;;;33445:32:1;;33440:2;33425:18;;33418:60;33514:22;;;33509:2;33494:18;;33487:50;33554:61;33518:6;33600;33592;33554:61;:::i;33626:597::-;-1:-1:-1;;;;;33925:32:1;;;33907:51;;33989:2;33974:18;;33967:34;;;;34037:32;;;;34032:2;34017:18;;34010:60;34101:2;34086:18;;34079:34;34144:3;34129:19;;34122:35;;;;34201:14;;34194:22;33945:3;34173:19;;34166:51;33894:3;33879:19;;33626:597::o;35036:343::-;35115:6;35123;35176:2;35164:9;35155:7;35151:23;35147:32;35144:52;;;35192:1;35189;35182:12;35144:52;-1:-1:-1;;35237:16:1;;35343:2;35328:18;;;35322:25;35237:16;;35322:25;;-1:-1:-1;35036:343:1:o;35384:217::-;35424:1;35450;35440:132;;35494:10;35489:3;35485:20;35482:1;35475:31;35529:4;35526:1;35519:15;35557:4;35554:1;35547:15;35440:132;-1:-1:-1;35586:9:1;;35384:217::o;35606:168::-;35679:9;;;35710;;35727:15;;;35721:22;;35707:37;35697:71;;35748:18;;:::i;36044:1609::-;36354:1;36350;36345:3;36341:11;36337:19;36329:6;36325:32;36314:9;36307:51;36394:6;36389:2;36378:9;36374:18;36367:34;36466:1;36462;36457:3;36453:11;36449:19;36441:6;36437:32;36432:2;36421:9;36417:18;36410:60;36506:3;36501:2;36490:9;36486:18;36479:31;36288:4;36548:3;36537:9;36533:19;36625:1;36621;36616:3;36612:11;36608:19;36599:6;36593:13;36589:39;36583:3;36572:9;36568:19;36561:68;36684:2;36676:6;36672:15;36666:22;36660:3;36649:9;36645:19;36638:51;36772:1;36768;36763:3;36759:11;36755:19;36749:2;36741:6;36737:15;36731:22;36727:48;36720:4;36709:9;36705:20;36698:78;36831:2;36823:6;36819:15;36813:22;36807:3;36796:9;36792:19;36785:51;36883:3;36875:6;36871:16;36865:23;36925:4;36919:3;36908:9;36904:19;36897:33;36950:6;36985:12;36979:19;37022:6;37014;37007:22;37060:3;37049:9;37045:19;37038:26;;37123:3;37113:6;37110:1;37106:14;37095:9;37091:30;37087:40;37073:54;;37168:2;37154:12;37150:21;37136:35;;37189:1;37199:261;37213:6;37210:1;37207:13;37199:261;;;37306:3;37302:8;37290:9;37282:6;37278:22;37274:37;37269:3;37262:50;37335:45;37373:6;37364;37358:13;37335:45;:::i;:::-;37325:55;-1:-1:-1;37415:2:1;37403:15;;;;37438:12;;;;;37235:1;37228:9;37199:261;;;-1:-1:-1;;;;37509:3:1;37497:16;;37491:23;37555:22;;;-1:-1:-1;;37551:37:1;37545:3;37530:19;;37523:66;37606:41;37559:6;37491:23;37606:41;:::i;38034:301::-;38163:3;38201:6;38195:13;38247:6;38240:4;38232:6;38228:17;38223:3;38217:37;38309:1;38273:16;;38298:13;;;-1:-1:-1;38273:16:1;38034:301;-1:-1:-1;38034:301:1:o
Swarm Source
ipfs://74fb7caf678ec10c7ddfffe1fc72b7e28011c552aa37a2b16c4ca7bf2a51e558
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.