Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 1,064 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Deposit As Colla... | 51305823 | 3 hrs ago | IN | 0 MON | 0.04472822 | ||||
| Redeem | 51273097 | 7 hrs ago | IN | 0 MON | 0.11466554 | ||||
| Redeem | 51264705 | 8 hrs ago | IN | 0 MON | 0.09818088 | ||||
| Deposit As Colla... | 51227809 | 12 hrs ago | IN | 0 MON | 0.03959145 | ||||
| Redeem | 51222261 | 13 hrs ago | IN | 0 MON | 0.0717293 | ||||
| Deposit As Colla... | 51212650 | 14 hrs ago | IN | 0 MON | 0.03868233 | ||||
| Redeem | 51099637 | 26 hrs ago | IN | 0 MON | 0.11040631 | ||||
| Redeem | 51093254 | 27 hrs ago | IN | 0 MON | 0.11152422 | ||||
| Deposit As Colla... | 51071991 | 29 hrs ago | IN | 0 MON | 0.04384944 | ||||
| Deposit As Colla... | 50867358 | 2 days ago | IN | 0 MON | 0.05942214 | ||||
| Redeem | 50850925 | 2 days ago | IN | 0 MON | 0.03546254 | ||||
| Transfer | 50826644 | 2 days ago | IN | 0 MON | 0.04596803 | ||||
| Deposit As Colla... | 50791559 | 2 days ago | IN | 0 MON | 0.03959145 | ||||
| Deposit As Colla... | 50781124 | 2 days ago | IN | 0 MON | 0.03969326 | ||||
| Deposit As Colla... | 50770462 | 2 days ago | IN | 0 MON | 0.0594177 | ||||
| Redeem | 50650771 | 3 days ago | IN | 0 MON | 0.1126285 | ||||
| Set Delegate App... | 50639287 | 3 days ago | IN | 0 MON | 0.00826618 | ||||
| Set Delegate App... | 50624218 | 3 days ago | IN | 0 MON | 0.00842826 | ||||
| Set Delegate App... | 50620451 | 3 days ago | IN | 0 MON | 0.01143392 | ||||
| Deposit As Colla... | 50611824 | 3 days ago | IN | 0 MON | 0.04022574 | ||||
| Deposit As Colla... | 50609236 | 3 days ago | IN | 0 MON | 0.05971342 | ||||
| Redeem | 50597867 | 3 days ago | IN | 0 MON | 0.11466554 | ||||
| Deposit As Colla... | 50590012 | 3 days ago | IN | 0 MON | 0.04473006 | ||||
| Deposit As Colla... | 50581011 | 3 days ago | IN | 0 MON | 0.05948039 | ||||
| Deposit As Colla... | 50570437 | 3 days ago | IN | 0 MON | 0.03255953 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 51312586 | 3 hrs ago | 0 MON | |||||
| 51312586 | 3 hrs ago | 0 MON | |||||
| 51312586 | 3 hrs ago | 0 MON | |||||
| 51305979 | 3 hrs ago | 0 MON | |||||
| 51305979 | 3 hrs ago | 0 MON | |||||
| 51305823 | 3 hrs ago | 0 MON | |||||
| 51305823 | 3 hrs ago | 0 MON | |||||
| 51305823 | 3 hrs ago | 0 MON | |||||
| 51305823 | 3 hrs ago | 0 MON | |||||
| 51273097 | 7 hrs ago | 0 MON | |||||
| 51273097 | 7 hrs ago | 0 MON | |||||
| 51273097 | 7 hrs ago | 0 MON | |||||
| 51273097 | 7 hrs ago | 0 MON | |||||
| 51273097 | 7 hrs ago | 0 MON | |||||
| 51264705 | 8 hrs ago | 0 MON | |||||
| 51264705 | 8 hrs ago | 0 MON | |||||
| 51264705 | 8 hrs ago | 0 MON | |||||
| 51264705 | 8 hrs ago | 0 MON | |||||
| 51264705 | 8 hrs ago | 0 MON | |||||
| 51228359 | 12 hrs ago | 0 MON | |||||
| 51228359 | 12 hrs ago | 0 MON | |||||
| 51227809 | 12 hrs ago | 0 MON | |||||
| 51227809 | 12 hrs ago | 0 MON | |||||
| 51227809 | 12 hrs ago | 0 MON | |||||
| 51227809 | 12 hrs ago | 0 MON |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BorrowableCToken
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity)
/**
*Submitted for verification at monadscan.com on 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
610100604052348015610010575f5ffd5b506040516169d13803806169d183398101604081905261002f91610630565b838383836001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561006e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610092919061068c565b8383838261009f8161035c565b6001600160a01b03908116608052821660c0819052604080516306fdde0360e01b815290516306fdde03916004808201925f929091908290030181865afa1580156100ec573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261011391908101906106b7565b604051602001610123919061077e565b60405160208183030381529060405260029081610140919061081f565b50816001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801561017c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101a391908101906106b7565b6040516020016101b391906108d9565b604051602081830303815290604052600390816101d0919061081f565b50816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023191906108ee565b60ff1660e052608051604051637d5528bd60e01b81526001600160a01b03838116600483015290911690637d5528bd90602401602060405180830381865afa15801561027f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102a3919061090e565b6102c0576040516365c906df60e11b815260040160405180910390fd5b6001600160a01b031660a052506102d890508161038d565b600655506102e991508290506103ba565b6103536080516001600160a01b031663d68dbfe46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034e919061068c565b6104b7565b5050505061092d565b61036d816399011ef160e01b610538565b61038a576040516369b5e45b60e11b815260040160405180910390fd5b50565b6203f48081118061039c575080155b1561038a57604051631961405760e31b815260040160405180910390fd5b6103cb81638ec124b360e01b610538565b6103dc576103dc638b5fe5a361055a565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa15801561043b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061045f919061068c565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a0329060600160405180910390a1505050565b6117708111156104ce576104ce638b5fe5a361055a565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b910160405180910390a15050565b5f61054283610563565b801561055357506105538383610596565b9392505050565b805f526004601cfd5b5f610575826301ffc9a760e01b610596565b8015610590575061058e826001600160e01b0319610596565b155b92915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015610606575060208210155b801561061157505f81115b979650505050505050565b6001600160a01b038116811461038a575f5ffd5b5f5f5f5f60808587031215610643575f5ffd5b845161064e8161061c565b602086015190945061065f8161061c565b60408601519093506106708161061c565b60608601519092506106818161061c565b939692955090935050565b5f6020828403121561069c575f5ffd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156106c7575f5ffd5b81516001600160401b038111156106dc575f5ffd5b8201601f810184136106ec575f5ffd5b80516001600160401b03811115610705576107056106a3565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610733576107336106a3565b60405281815282820160200186101561074a575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518060208401855e5f93019283525090919050565b68021bab93b30b731b2960bd1b81525f6105536009830184610767565b600181811c908216806107af57607f821691505b6020821081036107cd57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561081a57805f5260205f20601f840160051c810160208510156107f85750805b601f840160051c820191505b81811015610817575f8155600101610804565b50505b505050565b81516001600160401b03811115610838576108386106a3565b61084c81610846845461079b565b846107d3565b6020601f82116001811461087e575f83156108675750848201515b5f19600385901b1c1916600184901b178455610817565b5f84815260208120601f198516915b828110156108ad578785015182556020948501946001909201910161088d565b50848210156108ca57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b606360f81b81525f6105536001830184610767565b5f602082840312156108fe575f5ffd5b815160ff81168114610553575f5ffd5b5f6020828403121561091e575f5ffd5b81518015158114610553575f5ffd5b60805160a05160c05160e051615f2f610aa25f395f818161061701528181610f7a015261378101525f818161068401528181610e9301528181610f51015281816115dd0152818161167001528181612c6401528181612ed2015281816136fa0152818161376001528181613e1f01528181614490015281816149910152614c8701525f81816106db0152818161108a0152818161130f01528181611392015281816114b6015281816117c501528181611b8901528181611e1d01528181611ecc01528181611fc00152818161237b01528181612def015281816132be01528181613471015281816135610152818161372b0152818161409a015281816141a401528181614330015281816145da01528181614a640152614c4b01525f81816108e501528181610e0e01528181611aa6015281816120e0015281816124970152818161253d0152818161296b015281816129da0152818161319b0152818161392f01528181613c140152613f720152615f2f5ff3fe608060405234801561000f575f5ffd5b506004361061047a575f3560e01c806372d46ac211610258578063b3d7f6b91161014b578063d4bb0c73116100ca578063e28d591d1161008f578063e28d591d14610ad9578063e6248d5514610af8578063e8bbf5d714610b0b578063ef8b30f714610b2b578063f0c00c4114610b3e578063f411029114610b46575f5ffd5b8063d4bb0c7314610a6f578063d505accf14610a82578063d905777e14610a95578063dd62ed3e14610aa8578063deee770414610ad0575f5ffd5b8063c63d75b611610110578063c63d75b6146106b0578063c6e6f59214610a23578063cd88c07214610a36578063ce96cb7714610a49578063cf6af22d14610a5c575f5ffd5b8063b3d7f6b9146109c4578063b460af94146109d7578063ba087652146109ea578063bdca6723146109fd578063c3c854b614610a10575f5ffd5b806394bf804d116101d7578063a7af467a1161019c578063a7af467a14610970578063a9059cbb14610983578063ab21e62814610996578063ad9d3683146109a9578063b3bffb45146109b1575f5ffd5b806394bf804d1461090757806395d89b411461091a5780639616756e146109225780639e591a4414610935578063a75df49814610948575f5ffd5b80637ecebe001161021d5780637ecebe001461089757806380fd997f146108bc57806385b13080146108c557806387367d71146108d85780638f73dcfa146108e0575f5ffd5b806372d46ac2146108385780637313ee5a1461084b578063775a814a146108545780637ada7a091461085c5780637c0e0c8c1461086f575f5ffd5b806338d52e0f116103705780635722baf3116102ef578063635d9771116102b4578063635d9771146107af578063640fef7b146107da5780636779db5b146107ed5780636e553f651461080057806370a0823114610813575f5ffd5b80635722baf31461075057806357d159d5146107635780635b56d6f5146107765780635c0bfa88146107895780635fec5d0b1461079c575f5ffd5b806345d7b97a1161033557806345d7b97a146106fd5780634b3fd148146107045780634cdad5061461071757806350f2012f1461072a5780635296a4311461073d575f5ffd5b806338d52e0f146106825780633ba0b9a9146106a8578063402d267d146106b057806340c09eba146106c357806341ed2c12146106d6575f5ffd5b80631dd19cb4116103fc578063313ce567116103c1578063313ce567146106105780633237c158146106415780633644e51514610654578063371fd8e61461065c57806338c0f3091461066f575f5ffd5b80631dd19cb41461054a5780631e75db1614610552578063215702561461057d57806323b872dd146105ea5780632f4a61d9146105fd575f5ffd5b80630a28a477116104425780630a28a477146104f75780630f0f54361461050a57806311005b071461051f578063176679671461053257806318160ddd1461053a575f5ffd5b806301e1d1141461047e57806301ffc9a71461049957806306fdde03146104bc57806307a2d13a146104d1578063095ea7b3146104e4575b5f5ffd5b610486610b4e565b6040519081526020015b60405180910390f35b6104ac6104a7366004614f3b565b610b79565b6040519015158152602001610490565b6104c4610bca565b6040516104909190614f90565b6104866104df366004614fa2565b610c5a565b6104ac6104f2366004614fcd565b610c8e565b610486610505366004614fa2565b610cdd565b61051d61051836600461503e565b610cef565b005b61048661052d366004615090565b610d80565b610486600481565b6805345cdf77eb68f44c54610486565b61051d610dcf565b600854610565906001600160a01b031681565b6040516001600160a01b039091168152602001610490565b61059061058b366004615090565b610f0a565b604051610490919081516001600160a01b0390811682526020808401519091169082015260408083015160ff16908201526060808301511515908201526080808301519082015260a0918201519181019190915260c00190565b6104ac6105f83660046150ab565b610fdf565b61048661060b3660046150e9565b611037565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610490565b61051d61064f366004614fa2565b611137565b610486611183565b61051d61066a366004614fa2565b6111ff565b61051d61067d366004615117565b611243565b7f0000000000000000000000000000000000000000000000000000000000000000610565565b6104866112d9565b6104866106be366004615090565b6112ee565b61051d6106d13660046150e9565b611421565b6105657f000000000000000000000000000000000000000000000000000000000000000081565b60016104ac565b61051d6107123660046150e9565b611478565b610486610725366004614fa2565b61156d565b61051d610738366004614fa2565b61157a565b61051d61074b366004615198565b6115b7565b61051d61075e36600461520d565b611781565b610486610771366004615090565b611994565b61051d610784366004614fa2565b6119e2565b61048661079736600461528d565b611a24565b6104ac6107aa3660046152c1565b611a71565b6009546107c2906001600160f01b031681565b6040516001600160f01b039091168152602001610490565b61051d6107e836600461528d565b611b41565b6104866107fb36600461528d565b611c51565b61048661080e3660046150e9565b611c89565b610486610821366004615090565b6387a211a2600c9081525f91909152602090205490565b61048661084636600461528d565b611cd1565b61048660065481565b61051d611d08565b6104ac61086a366004615090565b611d47565b610877611d8e565b604080519485526020850193909352918301526060820152608001610490565b6104866108a5366004615090565b6338377508600c9081525f91909152602090205490565b61048661177081565b61051d6108d3366004615482565b611ddf565b61048661202c565b6105657f000000000000000000000000000000000000000000000000000000000000000081565b6104866109153660046150e9565b61207c565b6104c46120b0565b6104ac610930366004615090565b6120bf565b61051d6109433660046150e9565b61214b565b60095461095d90600160f01b900461ffff1681565b60405161ffff9091168152602001610490565b61048661097e366004614fa2565b612190565b6104ac610991366004614fcd565b61219f565b61051d6109a43660046150e9565b6121f5565b61048661223c565b6104866109bf3660046150e9565b61228a565b6104866109d2366004614fa2565b6122be565b6104866109e536600461528d565b6122d0565b6104866109f836600461528d565b612306565b61051d610a0b366004615618565b61233d565b61051d610a1e3660046156d0565b612459565b610486610a31366004614fa2565b612626565b610486610a4436600461528d565b612655565b610486610a57366004615090565b61268d565b610590610a6a366004615090565b6126aa565b61051d610a7d366004615090565b6126ec565b61051d610a903660046156fc565b6127af565b610486610aa3366004615090565b612931565b610486610ab63660046152c1565b602052637f5e9f20600c9081525f91909152603490205490565b61048660015481565b610486610ae7366004615090565b60056020525f908152604090205481565b610486610b06366004615090565b61294a565b610b1e610b1936600461576d565b6129d6565b60405161049091906157ab565b610486610b39366004614fa2565b612c38565b610486612c45565b610486612d1e565b5f688000000000ab143c065c15610b6c5763ab143c065f526004601cfd5b610b74612d37565b905090565b5f6001600160e01b03198216630934615b60e01b1480610ba957506001600160e01b0319821663b6e300c760e01b145b80610bc457506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610bd99061580e565b80601f0160208091040260200160405190810160405280929190818152602001828054610c059061580e565b8015610c505780601f10610c2757610100808354040283529160200191610c50565b820191905f5260205f20905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b5f688000000000ab143c065c15610c785763ab143c065f526004601cfd5b610bc482610c84612d37565b612d4d565b919050565b5f82602052637f5e9f20600c52335f52816034600c2055815f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa350600192915050565b5f610bc482610cea612d37565b612d80565b688000000000ab143c065c15610d0c5763ab143c065f526004601cfd5b30688000000000ab143c065d815f816001600160401b03811115610d3257610d326152ed565b604051908082528060200260200182016040528015610d5b578160200160208202803683370190505b509050610d6d8133878787875f612da6565b50505f688000000000ab143c065d505050565b6001600160a01b0381165f908152600a60205260408120546001600160b01b038116808303610db0575050919050565b600754610dc790829060b090811c9085901c61317a565b949350505050565b688000000000ab143c065c15610dec5763ab143c065f526004601cfd5b30688000000000ab143c065d610e00613186565b5f610e09612c45565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e68573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8c9190615846565b9050610eb97f00000000000000000000000000000000000000000000000000000000000000008284613220565b604080518381526001600160a01b03831660208201527f88fc2578c4b534418a67792f942c22deab48988e8f00bf87d4f8b0d0a8655772910160405180910390a150505f688000000000ab143c065d565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610f4483610d80565b3083526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016602084015290507f000000000000000000000000000000000000000000000000000000000000000060ff16604083015280610fad576001610faf565b5f5b151560608301526001600160a01b039092165f90815260056020526040902054608082015260a081019190915290565b5f688000000000ab143c065c15610ffd5763ab143c065f526004601cfd5b30688000000000ab143c065d611014828486613260565b61101f84848461338c565b50600190505f688000000000ab143c065d9392505050565b5f688000000000ab143c065c156110555763ab143c065f526004601cfd5b30688000000000ab143c065d336001600160a01b038316148015906110fd5750604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa1580156110d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fb9190615861565b155b1561110f5761110f63471656c5613433565b611119838361343c565b905061112581836134dc565b5f688000000000ab143c065d92915050565b688000000000ab143c065c156111545763ab143c065f526004601cfd5b30688000000000ab143c065d61116a8133613529565b6111748133613616565b5f688000000000ab143c065d50565b5f8061118d610bca565b8051906020012090506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81528160208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015260a081209250505090565b688000000000ab143c065c1561121c5763ab143c065f526004601cfd5b30688000000000ab143c065d6112338133336136b2565b505f688000000000ab143c065d50565b688000000000ab143c065c156112605763ab143c065f526004601cfd5b30688000000000ab143c065d8184811461128157611281638b5fe5a3613433565b6112c58686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525033925088915087905086866001612da6565b505f688000000000ab143c065d5050505050565b5f610b74670de0b6b3a7640000610c84612d37565b60405163699ba8b360e01b81523060048201525f9081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063699ba8b390602401606060405180830381865afa158015611354573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113789190615890565b5050604051637bca031760e11b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f794062e90602401602060405180830381865afa1580156113df573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114039190615861565b158061140c5750805b156114175750919050565b5f195b9392505050565b688000000000ab143c065c1561143e5763ab143c065f526004601cfd5b30688000000000ab143c065d61145481336138fd565b61145e82826139e0565b61146882826134dc565b5f688000000000ab143c065d5050565b688000000000ab143c065c156114955763ab143c065f526004601cfd5b30688000000000ab143c065d6114a9613a32565b6009546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f96492c9903090859033906114f79083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b15801561154c575f5ffd5b505af115801561155e573d5f5f3e3d5ffd5b50505050611468828233613d5a565b5f610bc482610c84612d37565b688000000000ab143c065c156115975763ab143c065f526004601cfd5b30688000000000ab143c065d6115ad81336139e0565b61117481336134dc565b6115bf613a32565b6115c883613e93565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561162a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164e91906158e2565b83111561166e5760405163ab2169c760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000005f61169985612190565b90505f6116a682876158cf565b90506116b3833388613220565b604051637924fd7d60e01b81523390637924fd7d906116dc90899085908a908a906004016158f9565b6020604051808303815f875af11580156116f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061171c91906158e2565b5061172983333084613ea8565b8160045461173791906158cf565b6004556040805187815260208101849052338183015290517fb216ab52d7988a2a0e79070667f92d2ade5e6464ee97984d5983afe3572348269181900360600190a1505050505050565b688000000000ab143c065c1561179e5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630eaa39a960e31b81523060048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637551cd48906044015f604051808303815f87803b15801561180e575f5ffd5b505af1158015611820573d5f5f3e3d5ffd5b508392505f915081905080805b848110156119695789898281811061184757611847615935565b905060200201359250825f03156119615786868281811061186a5761186a615935565b905060200201602081019061187f9190615090565b915061188b83856158cf565b6001600160a01b0383165f908152600560205260409020549094506118b1908490615949565b6001600160a01b0383165f81815260056020908152604080832094909455835187815290810191909152918201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda69060600160405180910390a1611917828985613ef7565b604080518481526001600160a01b038a8116602083015284168183015290517f6ee556dbce23a24ad3b539ee42191a2dd262b16ecb4d0ef20dbeb4bb5a9a23839181900360600190a15b60010161182d565b50826001546119789190615949565b600155505f9250688000000000ab143c069150505d5050505050565b5f688000000000ab143c065c156119b25763ab143c065f526004601cfd5b30688000000000ab143c065d6119c6613a32565b6119cf82610d80565b90505f688000000000ab143c065d919050565b688000000000ab143c065c156119ff5763ab143c065f526004601cfd5b30688000000000ab143c065d611a13613f5d565b611a1b613a32565b61117481613fa9565b5f688000000000ab143c065c15611a425763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c84848460015f614023565b90505f688000000000ab143c065d9392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529092909183917f0000000000000000000000000000000000000000000000000000000000000000169063e6248d5590602401602060405180830381865afa158015611aeb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0f91906158e2565b815260208082019290925260409081015f9081206001600160a01b039095168152939091529091205460ff1692915050565b688000000000ab143c065c15611b5e5763ab143c065f526004601cfd5b30688000000000ab143c065d611b7481336138fd565b611b7c613a32565b6009546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f96492c990309086908590611bca9083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b158015611c1f575f5ffd5b505af1158015611c31573d5f5f3e3d5ffd5b50505050611c40838383613d5a565b5f688000000000ab143c065d505050565b5f688000000000ab143c065c15611c6f5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c848484600180614023565b5f688000000000ab143c065c15611ca75763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd838361343c565b90505f688000000000ab143c065d92915050565b5f688000000000ab143c065c15611cef5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484846001614142565b688000000000ab143c065c15611d255763ab143c065f526004601cfd5b30688000000000ab143c065d611d39613a32565b5f688000000000ab143c065d565b5f688000000000ab143c065c15611d655763ab143c065f526004601cfd5b30688000000000ab143c065d611d7a8261424b565b5060015f688000000000ab143c065d919050565b5f5f5f5f688000000000ab143c065c15611daf5763ab143c065f526004601cfd5b50506007546001600160601b0381169364ffffffffff606083901c81169450608883901c16925060b09190911c90565b688000000000ab143c065c15611dfc5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa158015611e6a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8e9190615861565b611e9f57611e9f63471656c5613433565b611ea7613a32565b60405163463aea7f60e11b81523060048201526001600160a01b0383811660248301527f00000000000000000000000000000000000000000000000000000000000000001690638c75d4fe906044015f604051808303815f87803b158015611f0d575f5ffd5b505af1158015611f1f573d5f5f3e3d5ffd5b50505050611f2e833384613d5a565b6040516318f9a83960e21b815233906363e6a0e490611f579030908790879087906004016159b4565b5f604051808303815f87803b158015611f6e575f5ffd5b505af1158015611f80573d5f5f3e3d5ffd5b5050600954604051630967a76b60e31b81523060048201525f60248201526001600160a01b0386811660448301526001600160f01b0390921660648201527f00000000000000000000000000000000000000000000000000000000000000009091169250634b3d3b5891506084015f604051808303815f87803b158015612005575f5ffd5b505af1158015612017573d5f5f3e3d5ffd5b505050505f688000000000ab143c065d505050565b6004545f90808203612051576040516354e9f59b60e01b815260040160405180910390fd5b60095462012fd19061206c906001600160f01b031683615949565b6120769190615949565b91505090565b5f688000000000ab143c065c1561209a5763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd8383614309565b606060038054610bd99061580e565b604051634b0b3ab760e11b81526001600160a01b0382811660048301525f917f000000000000000000000000000000000000000000000000000000000000000090911690639616756e90602401602060405180830381865afa158015612127573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc49190615861565b688000000000ab143c065c156121685763ab143c065f526004601cfd5b30688000000000ab143c065d61217f8233836136b2565b505f688000000000ab143c065d5050565b5f610bc482600461271061317a565b5f688000000000ab143c065c156121bd5763ab143c065f526004601cfd5b30688000000000ab143c065d6121d4828433613260565b6121de83836143a9565b50600190505f688000000000ab143c065d92915050565b688000000000ab143c065c156122125763ab143c065f526004601cfd5b30688000000000ab143c065d61222881336138fd565b6122328282613529565b6114688282613616565b5f688000000000ab143c065c1561225a5763ab143c065f526004601cfd5b30688000000000ab143c065d61226e613a32565b506009546001600160f01b03165f688000000000ab143c065d90565b5f688000000000ab143c065c156122a85763ab143c065f526004601cfd5b30688000000000ab143c065d61110f82336138fd565b5f610bc4826122cb612d37565b61440d565b5f688000000000ab143c065c156122ee5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f614142565b5f688000000000ab143c065c156123245763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f5f614023565b688000000000ab143c065c1561235a5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa1580156123c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ec9190615861565b6123fd576123fd63471656c5613433565b612405613a32565b5f61240e612d37565b90505f61241c858584614433565b90505f6124298684612d80565b90506124388682333389614478565b612445868287858861451d565b5050505f688000000000ab143c065d505050565b336001600160a01b0383160361248257604051636eef2f3f60e11b815260040160405180910390fd5b604051634b0b3ab760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639616756e90602401602060405180830381865afa1580156124e4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125089190615861565b15612526576040516302d5da9f60e01b815260040160405180910390fd5b60405163e6248d5560e01b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e6248d5590602401602060405180830381865afa15801561258a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125ae91906158e2565b335f8181526020818152604080832085845282528083206001600160a01b03891680855290835292819020805460ff191688151590811790915581518681529283015293945090927ffeeb3502e62327bd3fece59983b972dc941e6abedd652971aac3adea23cf7e17910160405180910390a3505050565b5f688000000000ab143c065c156126445763ab143c065f526004601cfd5b610bc482612650612d37565b614671565b5f688000000000ab143c065c156126735763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f6001614023565b6387a211a2600c9081525f828152602090912054610bc490610c5a565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a08101919091526126e3613a32565b610bc482610f0a565b688000000000ab143c065c156127095763ab143c065f526004601cfd5b30688000000000ab143c065d61271d613f5d565b612725613a32565b600654816001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612764573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278891906158e2565b146127a657604051631961405760e31b815260040160405180910390fd5b61117481614697565b5f6127b8610bca565b805190602001209050844211156127d657631a15a3cc5f526004601cfd5b6040518860601b60601c98508760601b60601c975065383775081901600e52885f526020600c2080547f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528360208401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604084015246606084015230608084015260a08320602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60208401528960408401528860608401528060808401528760a084015260c08320604e526042602c205f528660ff16602052856040528460605260208060805f60015afa8b3d51146128de5763ddafbaef5f526004601cfd5b0190556303faf4f960a51b88176040526034602c2087905587897f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602060608501a360405250505f606052505050505050565b6387a211a2600c9081525f828152602090912054610bc4565b60405163e6248d5560e01b81526001600160a01b0382811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063e6248d5590602401602060405180830381865afa1580156129b2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc491906158e2565b60607f000000000000000000000000000000000000000000000000000000000000000082806001600160401b03811115612a1257612a126152ed565b604051908082528060200260200182016040528015612a4557816020015b6060815260200190600190039081612a305790505b5060408051606080820183525f80835260208301819052928201529194505b82811015612c2e57868682818110612a7e57612a7e615935565b9050602002810190612a909190615a55565b612a9990615a73565b9150816020015115612bd057815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa158015612aed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b119190615846565b90506001600160a01b038116612b3a57604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d792612b6f9233929190600401615adb565b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050612bad835f01518460400151614795565b868381518110612bbf57612bbf615935565b602002602001018190525050612c26565b81516001600160a01b03163014612bfa57604051637720ccd960e01b815260040160405180910390fd5b612c0830836040015161480a565b858281518110612c1a57612c1a615935565b60200260200101819052505b600101612a64565b5050505092915050565b5f610bc482612650612d37565b600480546040516370a0823160e01b815230928101929092525f9182907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612cb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906158e2565b600954612ceb91906001600160f01b03166158cf565b9050818111612d0d5760405163c0883a5560e01b815260040160405180910390fd5b612d178282615949565b9250505090565b5f612d27613a32565b610b74670de0b6b3a7640000610c845b5f612d4061485e565b600454610b7491906158cf565b5f5f612d606805345cdf77eb68f44c5490565b90508015612d7857612d73848483614898565b610dc7565b509192915050565b5f5f612d936805345cdf77eb68f44c5490565b90508015612d7857612d73848285614934565b306001600160a01b03841603612dc357612dc3638b5fe5a3613433565b612dcb613a32565b612ded6040518060600160405280606081526020015f81526020015f81525090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663da11ee23898989896040518060e001604052808b6001600160a01b03168152602001306001600160a01b031681526020018a815260200189151581526020015f81526020015f81526020015f8152506040518663ffffffff1660e01b8152600401612e87959493929190615b7e565b5f604051808303815f875af1158015612ea2573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ec99190810190615c73565b98509050612efd7f000000000000000000000000000000000000000000000000000000000000000088308460200151613ea8565b60075460b01c5f8080805b87811015612ff1578c8181518110612f2257612f22615935565b60200260200101519350835f0315612fe9578a8a82818110612f4657612f46615935565b9050602002016020810190612f5b9190615090565b915083612f6783610d80565b612f719190615949565b6001600160a01b0383165f908152600a6020526040902060b087901b82179055925060408051858152602081018590526001600160a01b03808f169282019290925290831660608201527f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9060800160405180910390a15b600101612f08565b5084604001518560200181815161300891906158cf565b90525060208501516009546001600160f01b0316101561303757600980546001600160f01b0319169055613073565b602085015160095461305291906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408501511561310c5760045460408601516130939062012fd1906158cf565b8110156130b35760405163ab2169c760e01b815260040160405180910390fd5b60408601516130c29082615949565b60045560408681015181519081526001600160a01b038e1660208201527f92fa6dfbfde0da658c7f8f7d12d2019a8b1972ebf52e449498652ade0455ba2c910160405180910390a1505b8451604051635722baf360e01b81526001600160a01b038a1691635722baf39161313f91908f908f908f90600401615d1d565b5f604051808303815f87803b158015613156575f5ffd5b505af1158015613168573d5f5f3e3d5ffd5b50505050505050505050505050505050565b5f610dc7848484614960565b6040516355eaece960e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063abd5d9d2906024015b602060405180830381865afa1580156131e9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320d9190615861565b61321e5761321e63471656c5613433565b565b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f51141716613257576390b8ec185f526004601cfd5b5f603452505050565b613268613a32565b61327183613e93565b816001600160a01b0316816001600160a01b0316036132a25760405162640b4560e41b815260040160405180910390fd5b6001600160a01b038082165f90815260056020526040812054917f00000000000000000000000000000000000000000000000000000000000000001663b7b7f260308786613301816387a211a2600c9081525f91909152602090205490565b875f891161330f575f613312565b60015b6040518763ffffffff1660e01b815260040161333396959493929190615d51565b6020604051808303815f875af115801561334f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061337391906158e2565b90508015613385576133858184613616565b5050505050565b5f8360601b33602052637f5e9f208117600c526034600c20805460018101156133ca57808511156133c4576313be252b5f526004601cfd5b84810382555b50506387a211a28117600c526020600c208054808511156133f25763f4d678b85f526004601cfd5b84810382555050835f526020600c208381540181555082602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a3505060019392505050565b805f526004601cfd5b5f613445613a32565b61345c61345484612650612d37565b915081613e93565b6040516330ae91d160e21b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c2ba4744906024015f604051808303815f87803b1580156134ba575f5ffd5b505af11580156134cc573d5f5f3e3d5ffd5b50505050610bc48382338561498c565b6001600160a01b0381165f908152600a60205260409020546001600160b01b03161561351b576040516311dd629d60e21b815260040160405180910390fd5b6135258282614a26565b5050565b61353282613e93565b6001600160a01b0381165f908152600560205260409020548281101561355f5761355f63e6c95926613433565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632076d8e73085856135ac876387a211a2600c9081525f91909152602090205490565b8660016040518763ffffffff1660e01b81526004016135d096959493929190615d51565b6020604051808303815f875af11580156135ec573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361091906158e2565b50505050565b6001600160a01b0381165f90815260056020526040902054613639908390615949565b6001600160a01b0382165f9081526005602052604090205560015461365f908390615949565b600155604080518381525f60208201526001600160a01b038316918101919091527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda6906060015b60405180910390a15050565b5f6136bb613a32565b5f6136c583610d80565b905084156136d357846136d5565b805b94506136e085613e93565b808511156136f5576136f5638b5fe5a3613433565b6137217f0000000000000000000000000000000000000000000000000000000000000000853088613ea8565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016634b0319523061375b8885615949565b9350837f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526024810193909352908316604483015260ff166064820152908616608482015260a4015f604051808303815f87803b1580156137fe575f5ffd5b505af1158015613810573d5f5f3e3d5ffd5b50506007546001600160a01b0386165f908152600a602052604090206001600160b01b031990911684179055506138449050565b6009546001600160f01b031685111561386c57600980546001600160f01b03191690556138a4565b6009546138839086906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408051868152602081018390526001600160a01b03868116828401528516606082015290517f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9181900360800190a150929392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529290917f00000000000000000000000000000000000000000000000000000000000000009091169063e6248d5590602401602060405180830381865afa158015613976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399a91906158e2565b815260208082019290925260409081015f9081206001600160a01b038516825290925290205460ff16613525576040516367ee2b0160e11b815260040160405180910390fd5b6139e982613e93565b6387a211a2600c9081525f82905260209020546001600160a01b0382165f90815260056020526040902054613a1f9084906158cf565b11156135255761352563e6c95926613433565b60075464ffffffffff608882901c1642819003613a4d575050565b6009546004546001600160601b0384169164ffffffffff606086901c169160b086901c916001600160f01b0316905f613a888684878a614b3a565b9050844210613bb95760085494965086945f906001600160a01b031663589dc77b613ab161202c565b613abb85886158cf565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160408051808303815f875af1158015613afa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1e9190615d8a565b9097509050808080613b308942615949565b613b3a9190615dac565b613b449190615dcb565b613b4e91906158cf565b9050613b5a81876158cf565b60408051898152602081018390529197507f6ca03c3e1f9f2693eb4277ee4f449b9838fad99c363f5d54bacaf5f71a34afec910160405180910390a1613bab87613ba484876158cf565b888b614b3a565b613bb590836158cf565b9150505b6009545f90613bd7908390600160f01b900461ffff1661271061317a565b90508015613ca1575f613c0f82613bf56805345cdf77eb68f44c5490565b84613c0087896158cf565b613c0a9190615949565b614934565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c6e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c929190615846565b9050613c9e8183614b94565b50505b8115613d305784613cb383878761317a565b613cbd91906158cf565b9450613cc982856158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613cf382846158cf565b60045560408051838152602081018390527f4e32a70f9f06da2cec9f0079d5658935775123a5ce8d0d68de35d019a8d1c19c910160405180910390a15b5050505060609190911b4260881b1760b09190911b176001600160601b0391909116176007555050565b613d6383613e93565b613d6c83614bfd565b6001600160a01b0381165f9081526005602052604090205415613da257604051635d00c4f360e11b815260040160405180910390fd5b5f83613dad83610d80565b613db791906158cf565b6007546001600160a01b0384165f908152600a602052604090206001600160b01b0319909116821790559050600954613dfa9085906001600160f01b03166158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613e457f00000000000000000000000000000000000000000000000000000000000000008486613220565b60408051858152602081018390526001600160a01b0384168183015290517fbec1750eb40c00e8dc2e1c84babbddd5779eaa06c951ab2c66416d05910e7a739181900360600190a150505050565b80613ea55763c0883a555f526004601cfd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716613eea57637939f4245f526004601cfd5b5f60605260405250505050565b8260601b6387a211a28117600c526020600c20805480841115613f215763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a350505050565b60405163de0c7a7160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063de0c7a71906024016131ce565b611770811115613fc057613fc0638b5fe5a3613433565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b91016136a6565b5f61402c613a32565b5f614035612d37565b90505f61404f6140458984612d4d565b9350838784614433565b905084156140665761406186336138fd565b614070565b6140708689614c25565b6001600160a01b038681165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916140d79130918e918d9189918d90600401615d51565b6020604051808303815f875af11580156140f3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061411791906158e2565b90508015614129576141298188613616565b614136848a338b8b614478565b50505095945050505050565b5f61414b613a32565b5f614154612d37565b90505f614162878684614433565b905061417a856141728985612d80565b945084614c25565b6001600160a01b038581165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916141e191309189918c9189918d90600401615d51565b6020604051808303815f875af11580156141fd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061422191906158e2565b90508015614233576142338187613616565b6142408885338a8a614478565b505050949350505050565b6008546040805163ea12489f60e01b8152905130926001600160a01b03169163ea12489f9160048083019260209291908290030181865afa158015614292573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142b69190615846565b6001600160a01b0316146142d1576142d163471656c5613433565b6142da81614c40565b60b0670de0b6b3a7640000901b608842901b606042901b6001600160601b036007541617171760078190555050565b5f614312613a32565b61431b83613e93565b6040516330ae91d160e21b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c2ba4744906024015f604051808303815f87803b158015614379575f5ffd5b505af115801561438b573d5f5f3e3d5ffd5b50505050610bc461439e846122cb612d37565b91508184338561498c565b5f6387a211a2600c52335f526020600c208054808411156143d15763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c335f516020615eda5f395f51905f52602080a350600192915050565b5f5f6144206805345cdf77eb68f44c5490565b90508015612d7857612d73848483614934565b5f61443d84613e93565b506387a211a2600c9081525f839052602090205461445b8183612d4d565b84111561446f5761446f63e6c95926613433565b61141a84614bfd565b6144828185614d01565b61448b85614d62565b6144b67f00000000000000000000000000000000000000000000000000000000000000008387613220565b806001600160a01b0316826001600160a01b0316846001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db888860405161450e929190918252602082015260400190565b60405180910390a45050505050565b604051632748468360e11b81523390634e908d0690614546903090899088908790600401615de2565b5f604051808303815f87803b15801561455d575f5ffd5b505af115801561456f573d5f5f3e3d5ffd5b50506387a211a2600c9081525f869052602090205461459192508691506158cf565b82146145b05760405163350385ad60e11b815260040160405180910390fd5b6001600160a01b038381165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916146179130918a918a918a918990600401615d51565b6020604051808303815f875af1158015614633573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465791906158e2565b90508015614669576146698185613616565b505050505050565b5f5f6146846805345cdf77eb68f44c5490565b90508015612d7857612d73848285614898565b6146a881638ec124b360e01b614d76565b6146b9576146b9638b5fe5a3613433565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa158015614718573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061473c91906158e2565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a032906060015b60405180910390a1505050565b60605f5f846001600160a01b03165f856040516147b29190615ec3565b5f6040518083038185875af1925050503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b606091505b5091509150614801858383614d91565b95945050505050565b60605f5f846001600160a01b0316846040516148269190615ec3565b5f60405180830381855af49150503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b6007546009545f9190612076906001600160601b038316906001600160f01b031664ffffffffff606085901c811690608886901c16614b3a565b8282025f1983850981811082019003806148c757826148be5763ae47f7025f526004601cfd5b5081900461141a565b8083116148db5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f614940848484614898565b9050818385091561141a576001018061141a5763ae47f7025f526004601cfd5b5f825f19048411830215820261497d5763ad251c275f526004601cfd5b50910281810615159190040190565b6149b87f0000000000000000000000000000000000000000000000000000000000000000833087613ea8565b6149c184614dd9565b6149cb8184614b94565b806001600160a01b0316826001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78686604051614a19929190918252602082015260400190565b60405180910390a3613610565b5f82600154614a3591906158cf565b6040516301ac71bb60e11b81523060048201526001600160a01b038481166024830152604482018390529192507f000000000000000000000000000000000000000000000000000000000000000090911690630358e376906064015f604051808303815f87803b158015614aa7575f5ffd5b505af1158015614ab9573d5f5f3e3d5ffd5b5050506001600160a01b0383165f90815260056020526040902054614ae0915084906158cf565b6001600160a01b0383165f818152600560209081526040918290209390935560018481558151878152938401528201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda690606001614788565b5f5f85118015614b4957508282105b15610dc757614801834210614b7157614b628385615949565b614b6c9087615dcb565b614b85565b614b7b8342615949565b614b859087615dcb565b85670de0b6b3a7640000614de7565b6805345cdf77eb68f44c5481810181811015614bb75763e5cfe9575f526004601cfd5b806805345cdf77eb68f44c5550506387a211a2600c52815f526020600c208181540181555080602052600c5160601c5f5f516020615eda5f395f51905f52602080a35050565b80614c0661202c565b1015613ea55760405163ab2169c760e01b815260040160405180910390fd5b336001600160a01b0383161461352557613525823383614df3565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614614c7d57614c7d63471656c5613433565b3062012fd1614cae7f0000000000000000000000000000000000000000000000000000000000000000848484613ea8565b80614cb95f82614b94565b600482905560408051838152602081018390525f916001600160a01b038716917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101614a19565b6387a211a2600c52815f526020600c20805480831115614d285763f4d678b85f526004601cfd5b82900390556805345cdf77eb68f44c805482900390555f8181526001600160a01b0383165f516020615eda5f395f51905f52602083a35050565b80600454614d709190615949565b60045550565b5f614d8083614e31565b801561141a575061141a8383614e63565b6060614d9d8383614ee9565b8151158015614db457506001600160a01b0384163b155b15614dd2576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b80600454614d7091906158cf565b5f610dc7848484614f17565b81602052637f5e9f20600c52825f526034600c20805460018101156133855780831115614e27576313be252b5f526004601cfd5b9190910390555050565b5f614e43826301ffc9a760e01b614e63565b8015610bc45750614e5c826001600160e01b0319614e63565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015614ed3575060208210155b8015614ede57505f81115b979650505050505050565b816135255780515f03614f0f576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f825f190484118302158202614f345763ad251c275f526004601cfd5b5091020490565b5f60208284031215614f4b575f5ffd5b81356001600160e01b03198116811461141a575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61141a6020830184614f62565b5f60208284031215614fb2575f5ffd5b5035919050565b6001600160a01b0381168114613ea5575f5ffd5b5f5f60408385031215614fde575f5ffd5b8235614fe981614fb9565b946020939093013593505050565b5f5f83601f840112615007575f5ffd5b5081356001600160401b0381111561501d575f5ffd5b6020830191508360208260051b8501011115615037575f5ffd5b9250929050565b5f5f5f60408486031215615050575f5ffd5b83356001600160401b03811115615065575f5ffd5b61507186828701614ff7565b909450925050602084013561508581614fb9565b809150509250925092565b5f602082840312156150a0575f5ffd5b813561141a81614fb9565b5f5f5f606084860312156150bd575f5ffd5b83356150c881614fb9565b925060208401356150d881614fb9565b929592945050506040919091013590565b5f5f604083850312156150fa575f5ffd5b82359150602083013561510c81614fb9565b809150509250929050565b5f5f5f5f5f6060868803121561512b575f5ffd5b85356001600160401b03811115615140575f5ffd5b61514c88828901614ff7565b90965094505060208601356001600160401b0381111561516a575f5ffd5b61517688828901614ff7565b909450925050604086013561518a81614fb9565b809150509295509295909350565b5f5f5f604084860312156151aa575f5ffd5b8335925060208401356001600160401b038111156151c6575f5ffd5b8401601f810186136151d6575f5ffd5b80356001600160401b038111156151eb575f5ffd5b8660208284010111156151fc575f5ffd5b939660209190910195509293505050565b5f5f5f5f5f60608688031215615221575f5ffd5b85356001600160401b03811115615236575f5ffd5b61524288828901614ff7565b909650945050602086013561525681614fb9565b925060408601356001600160401b03811115615270575f5ffd5b61527c88828901614ff7565b969995985093965092949392505050565b5f5f5f6060848603121561529f575f5ffd5b8335925060208401356152b181614fb9565b9150604084013561508581614fb9565b5f5f604083850312156152d2575f5ffd5b82356152dd81614fb9565b9150602083013561510c81614fb9565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b0381118282101715615323576153236152ed565b60405290565b604051606081016001600160401b0381118282101715615323576153236152ed565b604051601f8201601f191681016001600160401b0381118282101715615373576153736152ed565b604052919050565b8035610c8981614fb9565b5f82601f830112615395575f5ffd5b81356001600160401b038111156153ae576153ae6152ed565b6153c1601f8201601f191660200161534b565b8181528460208386010111156153d5575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c08284031215615401575f5ffd5b615409615301565b9050813561541681614fb9565b815260208281013590820152604082013561543081614fb9565b6040820152606082013561544381614fb9565b60608201526080828101359082015260a08201356001600160401b0381111561546a575f5ffd5b61547684828501615386565b60a08301525092915050565b5f5f5f60608486031215615494575f5ffd5b8335925060208401356154a681614fb9565b915060408401356001600160401b038111156154c0575f5ffd5b840160c081870312156154d1575f5ffd5b6154d9615301565b6154e28261537b565b8152602082810135908201526154fa6040830161537b565b60408201526060828101359082015260808201356001600160401b03811115615521575f5ffd5b61552d888285016153f1565b60808301525060a08201356001600160401b0381111561554b575f5ffd5b61555788828501615386565b60a08301525080925050509250925092565b5f6001600160401b03821115615581576155816152ed565b5060051b60200190565b5f82601f83011261559a575f5ffd5b81356155ad6155a882615569565b61534b565b8082825260208201915060208360051b8601019250858311156155ce575f5ffd5b602085015b8381101561560e5780356001600160401b038111156155f0575f5ffd5b6155ff886020838a01016153f1565b845250602092830192016155d3565b5095945050505050565b5f5f5f6060848603121561562a575f5ffd5b83359250602084013561563c81614fb9565b915060408401356001600160401b03811115615656575f5ffd5b840160c08187031215615667575f5ffd5b61566f615301565b6156788261537b565b8152602082810135908201526156906040830161537b565b60408201526060828101359082015260808201356001600160401b038111156156b7575f5ffd5b61552d8882850161558b565b8015158114613ea5575f5ffd5b5f5f604083850312156156e1575f5ffd5b82356156ec81614fb9565b9150602083013561510c816156c3565b5f5f5f5f5f5f5f60e0888a031215615712575f5ffd5b873561571d81614fb9565b9650602088013561572d81614fb9565b95506040880135945060608801359350608088013560ff81168114615750575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f6020838503121561577e575f5ffd5b82356001600160401b03811115615793575f5ffd5b61579f85828601614ff7565b90969095509350505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561580257603f198786030184526157ed858351614f62565b945060209384019391909101906001016157d1565b50929695505050505050565b600181811c9082168061582257607f821691505b60208210810361584057634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215615856575f5ffd5b815161141a81614fb9565b5f60208284031215615871575f5ffd5b815161141a816156c3565b634e487b7160e01b5f52601160045260245ffd5b5f5f5f606084860312156158a2575f5ffd5b83516158ad816156c3565b60208501519093506158be816156c3565b6040850151909250615085816156c3565b80820180821115610bc457610bc461587c565b5f602082840312156158f2575f5ffd5b5051919050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610bc457610bc461587c565b80516001600160a01b03908116835260208083015190840152604080830151821690840152606080830151909116908301526080808201519083015260a08181015160c09184018290525f91610dc790850182614f62565b60018060a01b038516815283602082015260018060a01b03831660408201526080606082015260018060a01b038251166080820152602082015160a082015260018060a01b0360408301511660c0820152606082015160e08201525f608083015160c0610100840152615a2b61014084018261595c565b905060a0840151607f1984830301610120850152615a498282614f62565b98975050505050505050565b5f8235605e19833603018112615a69575f5ffd5b9190910192915050565b5f60608236031215615a83575f5ffd5b615a8b615329565b8235615a9681614fb9565b81526020830135615aa6816156c3565b602082015260408301356001600160401b03811115615ac3575f5ffd5b615acf36828601615386565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061480190830184614f62565b5f8151808452602084019350602083015f5b82811015615b36578151865260209586019590910190600101615b18565b5093949350505050565b8183526020830192505f815f5b84811015615b36578135615b6081614fb9565b6001600160a01b031686526020958601959190910190600101615b4d565b61014081525f615b92610140830188615b06565b6001600160a01b03871660208401528281036040840152615bb4818688615b40565b91505060018060a01b03835116606083015260018060a01b036020840151166080830152604083015160a08301526060830151151560c0830152608083015160e083015260a083015161010083015260c08301516101208301529695505050505050565b5f82601f830112615c27575f5ffd5b8151615c356155a882615569565b8082825260208201915060208360051b860101925085831115615c56575f5ffd5b602085015b8381101561560e578051835260209283019201615c5b565b5f5f60408385031215615c84575f5ffd5b82516001600160401b03811115615c99575f5ffd5b830160608186031215615caa575f5ffd5b615cb2615329565b81516001600160401b03811115615cc7575f5ffd5b615cd387828501615c18565b8252506020828101518183015260409283015192820192909252908401519092506001600160401b03811115615d07575f5ffd5b615d1385828601615c18565b9150509250929050565b606081525f615d2f6060830187615b06565b6001600160a01b03861660208401528281036040840152614ede818587615b40565b6001600160a01b03968716815260208101959095529290941660408401526060830152608082019290925290151560a082015260c00190565b5f5f60408385031215615d9b575f5ffd5b505080516020909101519092909150565b5f82615dc657634e487b7160e01b5f52601260045260245ffd5b500490565b8082028115828204841417610bc457610bc461587c565b60018060a01b038516815283602082015260018060a01b0383166040820152608060608201525f610140820160018060a01b038451166080840152602084015160a084015260018060a01b0360408501511660c0840152606084015160e0840152608084015160c0610100850152818151808452610160860191506101608160051b87010193506020830192505f5b81811015615ea35761015f19878603018352615e8e85855161595c565b94506020938401939290920191600101615e71565b5050505060a0840151838203607f1901610120850152615a498282614f62565b5f82518060208501845e5f92019182525091905056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122074fb7caf678ec10c7ddfffe1fc72b7e28011c552aa37a2b16c4ca7bf2a51e55864736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e8000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9440000000000000000000000005b1d3a91457f7ad854a559daacc0be18cd402d12
Deployed Bytecode
0x608060405234801561000f575f5ffd5b506004361061047a575f3560e01c806372d46ac211610258578063b3d7f6b91161014b578063d4bb0c73116100ca578063e28d591d1161008f578063e28d591d14610ad9578063e6248d5514610af8578063e8bbf5d714610b0b578063ef8b30f714610b2b578063f0c00c4114610b3e578063f411029114610b46575f5ffd5b8063d4bb0c7314610a6f578063d505accf14610a82578063d905777e14610a95578063dd62ed3e14610aa8578063deee770414610ad0575f5ffd5b8063c63d75b611610110578063c63d75b6146106b0578063c6e6f59214610a23578063cd88c07214610a36578063ce96cb7714610a49578063cf6af22d14610a5c575f5ffd5b8063b3d7f6b9146109c4578063b460af94146109d7578063ba087652146109ea578063bdca6723146109fd578063c3c854b614610a10575f5ffd5b806394bf804d116101d7578063a7af467a1161019c578063a7af467a14610970578063a9059cbb14610983578063ab21e62814610996578063ad9d3683146109a9578063b3bffb45146109b1575f5ffd5b806394bf804d1461090757806395d89b411461091a5780639616756e146109225780639e591a4414610935578063a75df49814610948575f5ffd5b80637ecebe001161021d5780637ecebe001461089757806380fd997f146108bc57806385b13080146108c557806387367d71146108d85780638f73dcfa146108e0575f5ffd5b806372d46ac2146108385780637313ee5a1461084b578063775a814a146108545780637ada7a091461085c5780637c0e0c8c1461086f575f5ffd5b806338d52e0f116103705780635722baf3116102ef578063635d9771116102b4578063635d9771146107af578063640fef7b146107da5780636779db5b146107ed5780636e553f651461080057806370a0823114610813575f5ffd5b80635722baf31461075057806357d159d5146107635780635b56d6f5146107765780635c0bfa88146107895780635fec5d0b1461079c575f5ffd5b806345d7b97a1161033557806345d7b97a146106fd5780634b3fd148146107045780634cdad5061461071757806350f2012f1461072a5780635296a4311461073d575f5ffd5b806338d52e0f146106825780633ba0b9a9146106a8578063402d267d146106b057806340c09eba146106c357806341ed2c12146106d6575f5ffd5b80631dd19cb4116103fc578063313ce567116103c1578063313ce567146106105780633237c158146106415780633644e51514610654578063371fd8e61461065c57806338c0f3091461066f575f5ffd5b80631dd19cb41461054a5780631e75db1614610552578063215702561461057d57806323b872dd146105ea5780632f4a61d9146105fd575f5ffd5b80630a28a477116104425780630a28a477146104f75780630f0f54361461050a57806311005b071461051f578063176679671461053257806318160ddd1461053a575f5ffd5b806301e1d1141461047e57806301ffc9a71461049957806306fdde03146104bc57806307a2d13a146104d1578063095ea7b3146104e4575b5f5ffd5b610486610b4e565b6040519081526020015b60405180910390f35b6104ac6104a7366004614f3b565b610b79565b6040519015158152602001610490565b6104c4610bca565b6040516104909190614f90565b6104866104df366004614fa2565b610c5a565b6104ac6104f2366004614fcd565b610c8e565b610486610505366004614fa2565b610cdd565b61051d61051836600461503e565b610cef565b005b61048661052d366004615090565b610d80565b610486600481565b6805345cdf77eb68f44c54610486565b61051d610dcf565b600854610565906001600160a01b031681565b6040516001600160a01b039091168152602001610490565b61059061058b366004615090565b610f0a565b604051610490919081516001600160a01b0390811682526020808401519091169082015260408083015160ff16908201526060808301511515908201526080808301519082015260a0918201519181019190915260c00190565b6104ac6105f83660046150ab565b610fdf565b61048661060b3660046150e9565b611037565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152602001610490565b61051d61064f366004614fa2565b611137565b610486611183565b61051d61066a366004614fa2565b6111ff565b61051d61067d366004615117565b611243565b7f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e8610565565b6104866112d9565b6104866106be366004615090565b6112ee565b61051d6106d13660046150e9565b611421565b6105657f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c94481565b60016104ac565b61051d6107123660046150e9565b611478565b610486610725366004614fa2565b61156d565b61051d610738366004614fa2565b61157a565b61051d61074b366004615198565b6115b7565b61051d61075e36600461520d565b611781565b610486610771366004615090565b611994565b61051d610784366004614fa2565b6119e2565b61048661079736600461528d565b611a24565b6104ac6107aa3660046152c1565b611a71565b6009546107c2906001600160f01b031681565b6040516001600160f01b039091168152602001610490565b61051d6107e836600461528d565b611b41565b6104866107fb36600461528d565b611c51565b61048661080e3660046150e9565b611c89565b610486610821366004615090565b6387a211a2600c9081525f91909152602090205490565b61048661084636600461528d565b611cd1565b61048660065481565b61051d611d08565b6104ac61086a366004615090565b611d47565b610877611d8e565b604080519485526020850193909352918301526060820152608001610490565b6104866108a5366004615090565b6338377508600c9081525f91909152602090205490565b61048661177081565b61051d6108d3366004615482565b611ddf565b61048661202c565b6105657f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b6104866109153660046150e9565b61207c565b6104c46120b0565b6104ac610930366004615090565b6120bf565b61051d6109433660046150e9565b61214b565b60095461095d90600160f01b900461ffff1681565b60405161ffff9091168152602001610490565b61048661097e366004614fa2565b612190565b6104ac610991366004614fcd565b61219f565b61051d6109a43660046150e9565b6121f5565b61048661223c565b6104866109bf3660046150e9565b61228a565b6104866109d2366004614fa2565b6122be565b6104866109e536600461528d565b6122d0565b6104866109f836600461528d565b612306565b61051d610a0b366004615618565b61233d565b61051d610a1e3660046156d0565b612459565b610486610a31366004614fa2565b612626565b610486610a4436600461528d565b612655565b610486610a57366004615090565b61268d565b610590610a6a366004615090565b6126aa565b61051d610a7d366004615090565b6126ec565b61051d610a903660046156fc565b6127af565b610486610aa3366004615090565b612931565b610486610ab63660046152c1565b602052637f5e9f20600c9081525f91909152603490205490565b61048660015481565b610486610ae7366004615090565b60056020525f908152604090205481565b610486610b06366004615090565b61294a565b610b1e610b1936600461576d565b6129d6565b60405161049091906157ab565b610486610b39366004614fa2565b612c38565b610486612c45565b610486612d1e565b5f688000000000ab143c065c15610b6c5763ab143c065f526004601cfd5b610b74612d37565b905090565b5f6001600160e01b03198216630934615b60e01b1480610ba957506001600160e01b0319821663b6e300c760e01b145b80610bc457506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610bd99061580e565b80601f0160208091040260200160405190810160405280929190818152602001828054610c059061580e565b8015610c505780601f10610c2757610100808354040283529160200191610c50565b820191905f5260205f20905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b5f688000000000ab143c065c15610c785763ab143c065f526004601cfd5b610bc482610c84612d37565b612d4d565b919050565b5f82602052637f5e9f20600c52335f52816034600c2055815f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa350600192915050565b5f610bc482610cea612d37565b612d80565b688000000000ab143c065c15610d0c5763ab143c065f526004601cfd5b30688000000000ab143c065d815f816001600160401b03811115610d3257610d326152ed565b604051908082528060200260200182016040528015610d5b578160200160208202803683370190505b509050610d6d8133878787875f612da6565b50505f688000000000ab143c065d505050565b6001600160a01b0381165f908152600a60205260408120546001600160b01b038116808303610db0575050919050565b600754610dc790829060b090811c9085901c61317a565b949350505050565b688000000000ab143c065c15610dec5763ab143c065f526004601cfd5b30688000000000ab143c065d610e00613186565b5f610e09612c45565b90505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e68573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8c9190615846565b9050610eb97f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e88284613220565b604080518381526001600160a01b03831660208201527f88fc2578c4b534418a67792f942c22deab48988e8f00bf87d4f8b0d0a8655772910160405180910390a150505f688000000000ab143c065d565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610f4483610d80565b3083526001600160a01b037f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e816602084015290507f000000000000000000000000000000000000000000000000000000000000001260ff16604083015280610fad576001610faf565b5f5b151560608301526001600160a01b039092165f90815260056020526040902054608082015260a081019190915290565b5f688000000000ab143c065c15610ffd5763ab143c065f526004601cfd5b30688000000000ab143c065d611014828486613260565b61101f84848461338c565b50600190505f688000000000ab143c065d9392505050565b5f688000000000ab143c065c156110555763ab143c065f526004601cfd5b30688000000000ab143c065d336001600160a01b038316148015906110fd5750604051630a73e39160e01b81523360048201527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b031690630a73e39190602401602060405180830381865afa1580156110d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fb9190615861565b155b1561110f5761110f63471656c5613433565b611119838361343c565b905061112581836134dc565b5f688000000000ab143c065d92915050565b688000000000ab143c065c156111545763ab143c065f526004601cfd5b30688000000000ab143c065d61116a8133613529565b6111748133613616565b5f688000000000ab143c065d50565b5f8061118d610bca565b8051906020012090506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81528160208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015260a081209250505090565b688000000000ab143c065c1561121c5763ab143c065f526004601cfd5b30688000000000ab143c065d6112338133336136b2565b505f688000000000ab143c065d50565b688000000000ab143c065c156112605763ab143c065f526004601cfd5b30688000000000ab143c065d8184811461128157611281638b5fe5a3613433565b6112c58686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525033925088915087905086866001612da6565b505f688000000000ab143c065d5050505050565b5f610b74670de0b6b3a7640000610c84612d37565b60405163699ba8b360e01b81523060048201525f9081906001600160a01b037f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c944169063699ba8b390602401606060405180830381865afa158015611354573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113789190615890565b5050604051637bca031760e11b81523060048201529091507f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b03169063f794062e90602401602060405180830381865afa1580156113df573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114039190615861565b158061140c5750805b156114175750919050565b5f195b9392505050565b688000000000ab143c065c1561143e5763ab143c065f526004601cfd5b30688000000000ab143c065d61145481336138fd565b61145e82826139e0565b61146882826134dc565b5f688000000000ab143c065d5050565b688000000000ab143c065c156114955763ab143c065f526004601cfd5b30688000000000ab143c065d6114a9613a32565b6009546001600160a01b037f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c944169063f96492c9903090859033906114f79083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b15801561154c575f5ffd5b505af115801561155e573d5f5f3e3d5ffd5b50505050611468828233613d5a565b5f610bc482610c84612d37565b688000000000ab143c065c156115975763ab143c065f526004601cfd5b30688000000000ab143c065d6115ad81336139e0565b61117481336134dc565b6115bf613a32565b6115c883613e93565b6040516370a0823160e01b81523060048201527f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e86001600160a01b0316906370a0823190602401602060405180830381865afa15801561162a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164e91906158e2565b83111561166e5760405163ab2169c760e01b815260040160405180910390fd5b7f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e85f61169985612190565b90505f6116a682876158cf565b90506116b3833388613220565b604051637924fd7d60e01b81523390637924fd7d906116dc90899085908a908a906004016158f9565b6020604051808303815f875af11580156116f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061171c91906158e2565b5061172983333084613ea8565b8160045461173791906158cf565b6004556040805187815260208101849052338183015290517fb216ab52d7988a2a0e79070667f92d2ade5e6464ee97984d5983afe3572348269181900360600190a1505050505050565b688000000000ab143c065c1561179e5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630eaa39a960e31b81523060048201523360248201527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b031690637551cd48906044015f604051808303815f87803b15801561180e575f5ffd5b505af1158015611820573d5f5f3e3d5ffd5b508392505f915081905080805b848110156119695789898281811061184757611847615935565b905060200201359250825f03156119615786868281811061186a5761186a615935565b905060200201602081019061187f9190615090565b915061188b83856158cf565b6001600160a01b0383165f908152600560205260409020549094506118b1908490615949565b6001600160a01b0383165f81815260056020908152604080832094909455835187815290810191909152918201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda69060600160405180910390a1611917828985613ef7565b604080518481526001600160a01b038a8116602083015284168183015290517f6ee556dbce23a24ad3b539ee42191a2dd262b16ecb4d0ef20dbeb4bb5a9a23839181900360600190a15b60010161182d565b50826001546119789190615949565b600155505f9250688000000000ab143c069150505d5050505050565b5f688000000000ab143c065c156119b25763ab143c065f526004601cfd5b30688000000000ab143c065d6119c6613a32565b6119cf82610d80565b90505f688000000000ab143c065d919050565b688000000000ab143c065c156119ff5763ab143c065f526004601cfd5b30688000000000ab143c065d611a13613f5d565b611a1b613a32565b61117481613fa9565b5f688000000000ab143c065c15611a425763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c84848460015f614023565b90505f688000000000ab143c065d9392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529092909183917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff169063e6248d5590602401602060405180830381865afa158015611aeb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0f91906158e2565b815260208082019290925260409081015f9081206001600160a01b039095168152939091529091205460ff1692915050565b688000000000ab143c065c15611b5e5763ab143c065f526004601cfd5b30688000000000ab143c065d611b7481336138fd565b611b7c613a32565b6009546001600160a01b037f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c944169063f96492c990309086908590611bca9083906001600160f01b03166158cf565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b158015611c1f575f5ffd5b505af1158015611c31573d5f5f3e3d5ffd5b50505050611c40838383613d5a565b5f688000000000ab143c065d505050565b5f688000000000ab143c065c15611c6f5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c848484600180614023565b5f688000000000ab143c065c15611ca75763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd838361343c565b90505f688000000000ab143c065d92915050565b5f688000000000ab143c065c15611cef5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484846001614142565b688000000000ab143c065c15611d255763ab143c065f526004601cfd5b30688000000000ab143c065d611d39613a32565b5f688000000000ab143c065d565b5f688000000000ab143c065c15611d655763ab143c065f526004601cfd5b30688000000000ab143c065d611d7a8261424b565b5060015f688000000000ab143c065d919050565b5f5f5f5f688000000000ab143c065c15611daf5763ab143c065f526004601cfd5b50506007546001600160601b0381169364ffffffffff606083901c81169450608883901c16925060b09190911c90565b688000000000ab143c065c15611dfc5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b031690630a73e39190602401602060405180830381865afa158015611e6a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8e9190615861565b611e9f57611e9f63471656c5613433565b611ea7613a32565b60405163463aea7f60e11b81523060048201526001600160a01b0383811660248301527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9441690638c75d4fe906044015f604051808303815f87803b158015611f0d575f5ffd5b505af1158015611f1f573d5f5f3e3d5ffd5b50505050611f2e833384613d5a565b6040516318f9a83960e21b815233906363e6a0e490611f579030908790879087906004016159b4565b5f604051808303815f87803b158015611f6e575f5ffd5b505af1158015611f80573d5f5f3e3d5ffd5b5050600954604051630967a76b60e31b81523060048201525f60248201526001600160a01b0386811660448301526001600160f01b0390921660648201527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9449091169250634b3d3b5891506084015f604051808303815f87803b158015612005575f5ffd5b505af1158015612017573d5f5f3e3d5ffd5b505050505f688000000000ab143c065d505050565b6004545f90808203612051576040516354e9f59b60e01b815260040160405180910390fd5b60095462012fd19061206c906001600160f01b031683615949565b6120769190615949565b91505090565b5f688000000000ab143c065c1561209a5763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd8383614309565b606060038054610bd99061580e565b604051634b0b3ab760e11b81526001600160a01b0382811660048301525f917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff90911690639616756e90602401602060405180830381865afa158015612127573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc49190615861565b688000000000ab143c065c156121685763ab143c065f526004601cfd5b30688000000000ab143c065d61217f8233836136b2565b505f688000000000ab143c065d5050565b5f610bc482600461271061317a565b5f688000000000ab143c065c156121bd5763ab143c065f526004601cfd5b30688000000000ab143c065d6121d4828433613260565b6121de83836143a9565b50600190505f688000000000ab143c065d92915050565b688000000000ab143c065c156122125763ab143c065f526004601cfd5b30688000000000ab143c065d61222881336138fd565b6122328282613529565b6114688282613616565b5f688000000000ab143c065c1561225a5763ab143c065f526004601cfd5b30688000000000ab143c065d61226e613a32565b506009546001600160f01b03165f688000000000ab143c065d90565b5f688000000000ab143c065c156122a85763ab143c065f526004601cfd5b30688000000000ab143c065d61110f82336138fd565b5f610bc4826122cb612d37565b61440d565b5f688000000000ab143c065c156122ee5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f614142565b5f688000000000ab143c065c156123245763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f5f614023565b688000000000ab143c065c1561235a5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b031690630a73e39190602401602060405180830381865afa1580156123c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ec9190615861565b6123fd576123fd63471656c5613433565b612405613a32565b5f61240e612d37565b90505f61241c858584614433565b90505f6124298684612d80565b90506124388682333389614478565b612445868287858861451d565b5050505f688000000000ab143c065d505050565b336001600160a01b0383160361248257604051636eef2f3f60e11b815260040160405180910390fd5b604051634b0b3ab760e11b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031690639616756e90602401602060405180830381865afa1580156124e4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125089190615861565b15612526576040516302d5da9f60e01b815260040160405180910390fd5b60405163e6248d5560e01b81523360048201525f907f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063e6248d5590602401602060405180830381865afa15801561258a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125ae91906158e2565b335f8181526020818152604080832085845282528083206001600160a01b03891680855290835292819020805460ff191688151590811790915581518681529283015293945090927ffeeb3502e62327bd3fece59983b972dc941e6abedd652971aac3adea23cf7e17910160405180910390a3505050565b5f688000000000ab143c065c156126445763ab143c065f526004601cfd5b610bc482612650612d37565b614671565b5f688000000000ab143c065c156126735763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f6001614023565b6387a211a2600c9081525f828152602090912054610bc490610c5a565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a08101919091526126e3613a32565b610bc482610f0a565b688000000000ab143c065c156127095763ab143c065f526004601cfd5b30688000000000ab143c065d61271d613f5d565b612725613a32565b600654816001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612764573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278891906158e2565b146127a657604051631961405760e31b815260040160405180910390fd5b61117481614697565b5f6127b8610bca565b805190602001209050844211156127d657631a15a3cc5f526004601cfd5b6040518860601b60601c98508760601b60601c975065383775081901600e52885f526020600c2080547f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528360208401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604084015246606084015230608084015260a08320602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60208401528960408401528860608401528060808401528760a084015260c08320604e526042602c205f528660ff16602052856040528460605260208060805f60015afa8b3d51146128de5763ddafbaef5f526004601cfd5b0190556303faf4f960a51b88176040526034602c2087905587897f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602060608501a360405250505f606052505050505050565b6387a211a2600c9081525f828152602090912054610bc4565b60405163e6248d5560e01b81526001600160a01b0382811660048301525f917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff9091169063e6248d5590602401602060405180830381865afa1580156129b2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc491906158e2565b60607f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff82806001600160401b03811115612a1257612a126152ed565b604051908082528060200260200182016040528015612a4557816020015b6060815260200190600190039081612a305790505b5060408051606080820183525f80835260208301819052928201529194505b82811015612c2e57868682818110612a7e57612a7e615935565b9050602002810190612a909190615a55565b612a9990615a73565b9150816020015115612bd057815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa158015612aed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b119190615846565b90506001600160a01b038116612b3a57604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d792612b6f9233929190600401615adb565b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050612bad835f01518460400151614795565b868381518110612bbf57612bbf615935565b602002602001018190525050612c26565b81516001600160a01b03163014612bfa57604051637720ccd960e01b815260040160405180910390fd5b612c0830836040015161480a565b858281518110612c1a57612c1a615935565b60200260200101819052505b600101612a64565b5050505092915050565b5f610bc482612650612d37565b600480546040516370a0823160e01b815230928101929092525f9182907f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e86001600160a01b0316906370a0823190602401602060405180830381865afa158015612cb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906158e2565b600954612ceb91906001600160f01b03166158cf565b9050818111612d0d5760405163c0883a5560e01b815260040160405180910390fd5b612d178282615949565b9250505090565b5f612d27613a32565b610b74670de0b6b3a7640000610c845b5f612d4061485e565b600454610b7491906158cf565b5f5f612d606805345cdf77eb68f44c5490565b90508015612d7857612d73848483614898565b610dc7565b509192915050565b5f5f612d936805345cdf77eb68f44c5490565b90508015612d7857612d73848285614934565b306001600160a01b03841603612dc357612dc3638b5fe5a3613433565b612dcb613a32565b612ded6040518060600160405280606081526020015f81526020015f81525090565b7f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b031663da11ee23898989896040518060e001604052808b6001600160a01b03168152602001306001600160a01b031681526020018a815260200189151581526020015f81526020015f81526020015f8152506040518663ffffffff1660e01b8152600401612e87959493929190615b7e565b5f604051808303815f875af1158015612ea2573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ec99190810190615c73565b98509050612efd7f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e888308460200151613ea8565b60075460b01c5f8080805b87811015612ff1578c8181518110612f2257612f22615935565b60200260200101519350835f0315612fe9578a8a82818110612f4657612f46615935565b9050602002016020810190612f5b9190615090565b915083612f6783610d80565b612f719190615949565b6001600160a01b0383165f908152600a6020526040902060b087901b82179055925060408051858152602081018590526001600160a01b03808f169282019290925290831660608201527f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9060800160405180910390a15b600101612f08565b5084604001518560200181815161300891906158cf565b90525060208501516009546001600160f01b0316101561303757600980546001600160f01b0319169055613073565b602085015160095461305291906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408501511561310c5760045460408601516130939062012fd1906158cf565b8110156130b35760405163ab2169c760e01b815260040160405180910390fd5b60408601516130c29082615949565b60045560408681015181519081526001600160a01b038e1660208201527f92fa6dfbfde0da658c7f8f7d12d2019a8b1972ebf52e449498652ade0455ba2c910160405180910390a1505b8451604051635722baf360e01b81526001600160a01b038a1691635722baf39161313f91908f908f908f90600401615d1d565b5f604051808303815f87803b158015613156575f5ffd5b505af1158015613168573d5f5f3e3d5ffd5b50505050505050505050505050505050565b5f610dc7848484614960565b6040516355eaece960e11b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063abd5d9d2906024015b602060405180830381865afa1580156131e9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320d9190615861565b61321e5761321e63471656c5613433565b565b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f51141716613257576390b8ec185f526004601cfd5b5f603452505050565b613268613a32565b61327183613e93565b816001600160a01b0316816001600160a01b0316036132a25760405162640b4560e41b815260040160405180910390fd5b6001600160a01b038082165f90815260056020526040812054917f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9441663b7b7f260308786613301816387a211a2600c9081525f91909152602090205490565b875f891161330f575f613312565b60015b6040518763ffffffff1660e01b815260040161333396959493929190615d51565b6020604051808303815f875af115801561334f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061337391906158e2565b90508015613385576133858184613616565b5050505050565b5f8360601b33602052637f5e9f208117600c526034600c20805460018101156133ca57808511156133c4576313be252b5f526004601cfd5b84810382555b50506387a211a28117600c526020600c208054808511156133f25763f4d678b85f526004601cfd5b84810382555050835f526020600c208381540181555082602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a3505060019392505050565b805f526004601cfd5b5f613445613a32565b61345c61345484612650612d37565b915081613e93565b6040516330ae91d160e21b81523060048201527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b03169063c2ba4744906024015f604051808303815f87803b1580156134ba575f5ffd5b505af11580156134cc573d5f5f3e3d5ffd5b50505050610bc48382338561498c565b6001600160a01b0381165f908152600a60205260409020546001600160b01b03161561351b576040516311dd629d60e21b815260040160405180910390fd5b6135258282614a26565b5050565b61353282613e93565b6001600160a01b0381165f908152600560205260409020548281101561355f5761355f63e6c95926613433565b7f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b0316632076d8e73085856135ac876387a211a2600c9081525f91909152602090205490565b8660016040518763ffffffff1660e01b81526004016135d096959493929190615d51565b6020604051808303815f875af11580156135ec573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361091906158e2565b50505050565b6001600160a01b0381165f90815260056020526040902054613639908390615949565b6001600160a01b0382165f9081526005602052604090205560015461365f908390615949565b600155604080518381525f60208201526001600160a01b038316918101919091527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda6906060015b60405180910390a15050565b5f6136bb613a32565b5f6136c583610d80565b905084156136d357846136d5565b805b94506136e085613e93565b808511156136f5576136f5638b5fe5a3613433565b6137217f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e8853088613ea8565b6001600160a01b037f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c94416634b0319523061375b8885615949565b9350837f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e87f00000000000000000000000000000000000000000000000000000000000000126040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526024810193909352908316604483015260ff166064820152908616608482015260a4015f604051808303815f87803b1580156137fe575f5ffd5b505af1158015613810573d5f5f3e3d5ffd5b50506007546001600160a01b0386165f908152600a602052604090206001600160b01b031990911684179055506138449050565b6009546001600160f01b031685111561386c57600980546001600160f01b03191690556138a4565b6009546138839086906001600160f01b0316615949565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408051868152602081018390526001600160a01b03868116828401528516606082015290517f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9181900360800190a150929392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529290917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff9091169063e6248d5590602401602060405180830381865afa158015613976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399a91906158e2565b815260208082019290925260409081015f9081206001600160a01b038516825290925290205460ff16613525576040516367ee2b0160e11b815260040160405180910390fd5b6139e982613e93565b6387a211a2600c9081525f82905260209020546001600160a01b0382165f90815260056020526040902054613a1f9084906158cf565b11156135255761352563e6c95926613433565b60075464ffffffffff608882901c1642819003613a4d575050565b6009546004546001600160601b0384169164ffffffffff606086901c169160b086901c916001600160f01b0316905f613a888684878a614b3a565b9050844210613bb95760085494965086945f906001600160a01b031663589dc77b613ab161202c565b613abb85886158cf565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160408051808303815f875af1158015613afa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1e9190615d8a565b9097509050808080613b308942615949565b613b3a9190615dac565b613b449190615dcb565b613b4e91906158cf565b9050613b5a81876158cf565b60408051898152602081018390529197507f6ca03c3e1f9f2693eb4277ee4f449b9838fad99c363f5d54bacaf5f71a34afec910160405180910390a1613bab87613ba484876158cf565b888b614b3a565b613bb590836158cf565b9150505b6009545f90613bd7908390600160f01b900461ffff1661271061317a565b90508015613ca1575f613c0f82613bf56805345cdf77eb68f44c5490565b84613c0087896158cf565b613c0a9190615949565b614934565b90505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c6e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c929190615846565b9050613c9e8183614b94565b50505b8115613d305784613cb383878761317a565b613cbd91906158cf565b9450613cc982856158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613cf382846158cf565b60045560408051838152602081018390527f4e32a70f9f06da2cec9f0079d5658935775123a5ce8d0d68de35d019a8d1c19c910160405180910390a15b5050505060609190911b4260881b1760b09190911b176001600160601b0391909116176007555050565b613d6383613e93565b613d6c83614bfd565b6001600160a01b0381165f9081526005602052604090205415613da257604051635d00c4f360e11b815260040160405180910390fd5b5f83613dad83610d80565b613db791906158cf565b6007546001600160a01b0384165f908152600a602052604090206001600160b01b0319909116821790559050600954613dfa9085906001600160f01b03166158cf565b600980546001600160f01b0319166001600160f01b0392909216919091179055613e457f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e88486613220565b60408051858152602081018390526001600160a01b0384168183015290517fbec1750eb40c00e8dc2e1c84babbddd5779eaa06c951ab2c66416d05910e7a739181900360600190a150505050565b80613ea55763c0883a555f526004601cfd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716613eea57637939f4245f526004601cfd5b5f60605260405250505050565b8260601b6387a211a28117600c526020600c20805480841115613f215763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c8160601c5f516020615eda5f395f51905f52602080a350505050565b60405163de0c7a7160e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063de0c7a71906024016131ce565b611770811115613fc057613fc0638b5fe5a3613433565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b91016136a6565b5f61402c613a32565b5f614035612d37565b90505f61404f6140458984612d4d565b9350838784614433565b905084156140665761406186336138fd565b614070565b6140708689614c25565b6001600160a01b038681165f90815260056020526040808220549051632076d8e760e01b815291927f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9441691632076d8e7916140d79130918e918d9189918d90600401615d51565b6020604051808303815f875af11580156140f3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061411791906158e2565b90508015614129576141298188613616565b614136848a338b8b614478565b50505095945050505050565b5f61414b613a32565b5f614154612d37565b90505f614162878684614433565b905061417a856141728985612d80565b945084614c25565b6001600160a01b038581165f90815260056020526040808220549051632076d8e760e01b815291927f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9441691632076d8e7916141e191309189918c9189918d90600401615d51565b6020604051808303815f875af11580156141fd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061422191906158e2565b90508015614233576142338187613616565b6142408885338a8a614478565b505050949350505050565b6008546040805163ea12489f60e01b8152905130926001600160a01b03169163ea12489f9160048083019260209291908290030181865afa158015614292573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142b69190615846565b6001600160a01b0316146142d1576142d163471656c5613433565b6142da81614c40565b60b0670de0b6b3a7640000901b608842901b606042901b6001600160601b036007541617171760078190555050565b5f614312613a32565b61431b83613e93565b6040516330ae91d160e21b81523060048201527f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9446001600160a01b03169063c2ba4744906024015f604051808303815f87803b158015614379575f5ffd5b505af115801561438b573d5f5f3e3d5ffd5b50505050610bc461439e846122cb612d37565b91508184338561498c565b5f6387a211a2600c52335f526020600c208054808411156143d15763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c335f516020615eda5f395f51905f52602080a350600192915050565b5f5f6144206805345cdf77eb68f44c5490565b90508015612d7857612d73848483614934565b5f61443d84613e93565b506387a211a2600c9081525f839052602090205461445b8183612d4d565b84111561446f5761446f63e6c95926613433565b61141a84614bfd565b6144828185614d01565b61448b85614d62565b6144b67f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e88387613220565b806001600160a01b0316826001600160a01b0316846001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db888860405161450e929190918252602082015260400190565b60405180910390a45050505050565b604051632748468360e11b81523390634e908d0690614546903090899088908790600401615de2565b5f604051808303815f87803b15801561455d575f5ffd5b505af115801561456f573d5f5f3e3d5ffd5b50506387a211a2600c9081525f869052602090205461459192508691506158cf565b82146145b05760405163350385ad60e11b815260040160405180910390fd5b6001600160a01b038381165f90815260056020526040808220549051632076d8e760e01b815291927f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9441691632076d8e7916146179130918a918a918a918990600401615d51565b6020604051808303815f875af1158015614633573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465791906158e2565b90508015614669576146698185613616565b505050505050565b5f5f6146846805345cdf77eb68f44c5490565b90508015612d7857612d73848285614898565b6146a881638ec124b360e01b614d76565b6146b9576146b9638b5fe5a3613433565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa158015614718573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061473c91906158e2565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a032906060015b60405180910390a1505050565b60605f5f846001600160a01b03165f856040516147b29190615ec3565b5f6040518083038185875af1925050503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b606091505b5091509150614801858383614d91565b95945050505050565b60605f5f846001600160a01b0316846040516148269190615ec3565b5f60405180830381855af49150503d805f81146147ec576040519150601f19603f3d011682016040523d82523d5f602084013e6147f1565b6007546009545f9190612076906001600160601b038316906001600160f01b031664ffffffffff606085901c811690608886901c16614b3a565b8282025f1983850981811082019003806148c757826148be5763ae47f7025f526004601cfd5b5081900461141a565b8083116148db5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f614940848484614898565b9050818385091561141a576001018061141a5763ae47f7025f526004601cfd5b5f825f19048411830215820261497d5763ad251c275f526004601cfd5b50910281810615159190040190565b6149b87f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e8833087613ea8565b6149c184614dd9565b6149cb8184614b94565b806001600160a01b0316826001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78686604051614a19929190918252602082015260400190565b60405180910390a3613610565b5f82600154614a3591906158cf565b6040516301ac71bb60e11b81523060048201526001600160a01b038481166024830152604482018390529192507f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c94490911690630358e376906064015f604051808303815f87803b158015614aa7575f5ffd5b505af1158015614ab9573d5f5f3e3d5ffd5b5050506001600160a01b0383165f90815260056020526040902054614ae0915084906158cf565b6001600160a01b0383165f818152600560209081526040918290209390935560018481558151878152938401528201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda690606001614788565b5f5f85118015614b4957508282105b15610dc757614801834210614b7157614b628385615949565b614b6c9087615dcb565b614b85565b614b7b8342615949565b614b859087615dcb565b85670de0b6b3a7640000614de7565b6805345cdf77eb68f44c5481810181811015614bb75763e5cfe9575f526004601cfd5b806805345cdf77eb68f44c5550506387a211a2600c52815f526020600c208181540181555080602052600c5160601c5f5f516020615eda5f395f51905f52602080a35050565b80614c0661202c565b1015613ea55760405163ab2169c760e01b815260040160405180910390fd5b336001600160a01b0383161461352557613525823383614df3565b336001600160a01b037f000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9441614614c7d57614c7d63471656c5613433565b3062012fd1614cae7f000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e8848484613ea8565b80614cb95f82614b94565b600482905560408051838152602081018390525f916001600160a01b038716917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101614a19565b6387a211a2600c52815f526020600c20805480831115614d285763f4d678b85f526004601cfd5b82900390556805345cdf77eb68f44c805482900390555f8181526001600160a01b0383165f516020615eda5f395f51905f52602083a35050565b80600454614d709190615949565b60045550565b5f614d8083614e31565b801561141a575061141a8383614e63565b6060614d9d8383614ee9565b8151158015614db457506001600160a01b0384163b155b15614dd2576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b80600454614d7091906158cf565b5f610dc7848484614f17565b81602052637f5e9f20600c52825f526034600c20805460018101156133855780831115614e27576313be252b5f526004601cfd5b9190910390555050565b5f614e43826301ffc9a760e01b614e63565b8015610bc45750614e5c826001600160e01b0319614e63565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015614ed3575060208210155b8015614ede57505f81115b979650505050505050565b816135255780515f03614f0f576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f825f190484118302158202614f345763ad251c275f526004601cfd5b5091020490565b5f60208284031215614f4b575f5ffd5b81356001600160e01b03198116811461141a575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61141a6020830184614f62565b5f60208284031215614fb2575f5ffd5b5035919050565b6001600160a01b0381168114613ea5575f5ffd5b5f5f60408385031215614fde575f5ffd5b8235614fe981614fb9565b946020939093013593505050565b5f5f83601f840112615007575f5ffd5b5081356001600160401b0381111561501d575f5ffd5b6020830191508360208260051b8501011115615037575f5ffd5b9250929050565b5f5f5f60408486031215615050575f5ffd5b83356001600160401b03811115615065575f5ffd5b61507186828701614ff7565b909450925050602084013561508581614fb9565b809150509250925092565b5f602082840312156150a0575f5ffd5b813561141a81614fb9565b5f5f5f606084860312156150bd575f5ffd5b83356150c881614fb9565b925060208401356150d881614fb9565b929592945050506040919091013590565b5f5f604083850312156150fa575f5ffd5b82359150602083013561510c81614fb9565b809150509250929050565b5f5f5f5f5f6060868803121561512b575f5ffd5b85356001600160401b03811115615140575f5ffd5b61514c88828901614ff7565b90965094505060208601356001600160401b0381111561516a575f5ffd5b61517688828901614ff7565b909450925050604086013561518a81614fb9565b809150509295509295909350565b5f5f5f604084860312156151aa575f5ffd5b8335925060208401356001600160401b038111156151c6575f5ffd5b8401601f810186136151d6575f5ffd5b80356001600160401b038111156151eb575f5ffd5b8660208284010111156151fc575f5ffd5b939660209190910195509293505050565b5f5f5f5f5f60608688031215615221575f5ffd5b85356001600160401b03811115615236575f5ffd5b61524288828901614ff7565b909650945050602086013561525681614fb9565b925060408601356001600160401b03811115615270575f5ffd5b61527c88828901614ff7565b969995985093965092949392505050565b5f5f5f6060848603121561529f575f5ffd5b8335925060208401356152b181614fb9565b9150604084013561508581614fb9565b5f5f604083850312156152d2575f5ffd5b82356152dd81614fb9565b9150602083013561510c81614fb9565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b0381118282101715615323576153236152ed565b60405290565b604051606081016001600160401b0381118282101715615323576153236152ed565b604051601f8201601f191681016001600160401b0381118282101715615373576153736152ed565b604052919050565b8035610c8981614fb9565b5f82601f830112615395575f5ffd5b81356001600160401b038111156153ae576153ae6152ed565b6153c1601f8201601f191660200161534b565b8181528460208386010111156153d5575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c08284031215615401575f5ffd5b615409615301565b9050813561541681614fb9565b815260208281013590820152604082013561543081614fb9565b6040820152606082013561544381614fb9565b60608201526080828101359082015260a08201356001600160401b0381111561546a575f5ffd5b61547684828501615386565b60a08301525092915050565b5f5f5f60608486031215615494575f5ffd5b8335925060208401356154a681614fb9565b915060408401356001600160401b038111156154c0575f5ffd5b840160c081870312156154d1575f5ffd5b6154d9615301565b6154e28261537b565b8152602082810135908201526154fa6040830161537b565b60408201526060828101359082015260808201356001600160401b03811115615521575f5ffd5b61552d888285016153f1565b60808301525060a08201356001600160401b0381111561554b575f5ffd5b61555788828501615386565b60a08301525080925050509250925092565b5f6001600160401b03821115615581576155816152ed565b5060051b60200190565b5f82601f83011261559a575f5ffd5b81356155ad6155a882615569565b61534b565b8082825260208201915060208360051b8601019250858311156155ce575f5ffd5b602085015b8381101561560e5780356001600160401b038111156155f0575f5ffd5b6155ff886020838a01016153f1565b845250602092830192016155d3565b5095945050505050565b5f5f5f6060848603121561562a575f5ffd5b83359250602084013561563c81614fb9565b915060408401356001600160401b03811115615656575f5ffd5b840160c08187031215615667575f5ffd5b61566f615301565b6156788261537b565b8152602082810135908201526156906040830161537b565b60408201526060828101359082015260808201356001600160401b038111156156b7575f5ffd5b61552d8882850161558b565b8015158114613ea5575f5ffd5b5f5f604083850312156156e1575f5ffd5b82356156ec81614fb9565b9150602083013561510c816156c3565b5f5f5f5f5f5f5f60e0888a031215615712575f5ffd5b873561571d81614fb9565b9650602088013561572d81614fb9565b95506040880135945060608801359350608088013560ff81168114615750575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f6020838503121561577e575f5ffd5b82356001600160401b03811115615793575f5ffd5b61579f85828601614ff7565b90969095509350505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561580257603f198786030184526157ed858351614f62565b945060209384019391909101906001016157d1565b50929695505050505050565b600181811c9082168061582257607f821691505b60208210810361584057634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215615856575f5ffd5b815161141a81614fb9565b5f60208284031215615871575f5ffd5b815161141a816156c3565b634e487b7160e01b5f52601160045260245ffd5b5f5f5f606084860312156158a2575f5ffd5b83516158ad816156c3565b60208501519093506158be816156c3565b6040850151909250615085816156c3565b80820180821115610bc457610bc461587c565b5f602082840312156158f2575f5ffd5b5051919050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610bc457610bc461587c565b80516001600160a01b03908116835260208083015190840152604080830151821690840152606080830151909116908301526080808201519083015260a08181015160c09184018290525f91610dc790850182614f62565b60018060a01b038516815283602082015260018060a01b03831660408201526080606082015260018060a01b038251166080820152602082015160a082015260018060a01b0360408301511660c0820152606082015160e08201525f608083015160c0610100840152615a2b61014084018261595c565b905060a0840151607f1984830301610120850152615a498282614f62565b98975050505050505050565b5f8235605e19833603018112615a69575f5ffd5b9190910192915050565b5f60608236031215615a83575f5ffd5b615a8b615329565b8235615a9681614fb9565b81526020830135615aa6816156c3565b602082015260408301356001600160401b03811115615ac3575f5ffd5b615acf36828601615386565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061480190830184614f62565b5f8151808452602084019350602083015f5b82811015615b36578151865260209586019590910190600101615b18565b5093949350505050565b8183526020830192505f815f5b84811015615b36578135615b6081614fb9565b6001600160a01b031686526020958601959190910190600101615b4d565b61014081525f615b92610140830188615b06565b6001600160a01b03871660208401528281036040840152615bb4818688615b40565b91505060018060a01b03835116606083015260018060a01b036020840151166080830152604083015160a08301526060830151151560c0830152608083015160e083015260a083015161010083015260c08301516101208301529695505050505050565b5f82601f830112615c27575f5ffd5b8151615c356155a882615569565b8082825260208201915060208360051b860101925085831115615c56575f5ffd5b602085015b8381101561560e578051835260209283019201615c5b565b5f5f60408385031215615c84575f5ffd5b82516001600160401b03811115615c99575f5ffd5b830160608186031215615caa575f5ffd5b615cb2615329565b81516001600160401b03811115615cc7575f5ffd5b615cd387828501615c18565b8252506020828101518183015260409283015192820192909252908401519092506001600160401b03811115615d07575f5ffd5b615d1385828601615c18565b9150509250929050565b606081525f615d2f6060830187615b06565b6001600160a01b03861660208401528281036040840152614ede818587615b40565b6001600160a01b03968716815260208101959095529290941660408401526060830152608082019290925290151560a082015260c00190565b5f5f60408385031215615d9b575f5ffd5b505080516020909101519092909150565b5f82615dc657634e487b7160e01b5f52601260045260245ffd5b500490565b8082028115828204841417610bc457610bc461587c565b60018060a01b038516815283602082015260018060a01b0383166040820152608060608201525f610140820160018060a01b038451166080840152602084015160a084015260018060a01b0360408501511660c0840152606084015160e0840152608084015160c0610100850152818151808452610160860191506101608160051b87010193506020830192505f5b81811015615ea35761015f19878603018352615e8e85855161595c565b94506020938401939290920191600101615e71565b5050505060a0840151838203607f1901610120850152615a498282614f62565b5f82518060208501845e5f92019182525091905056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122074fb7caf678ec10c7ddfffe1fc72b7e28011c552aa37a2b16c4ca7bf2a51e55864736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001310f352f1389969ece6741671c4b919523912ff000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e8000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c9440000000000000000000000005b1d3a91457f7ad854a559daacc0be18cd402d12
-----Decoded View---------------
Arg [0] : cr (address): 0x1310f352f1389969Ece6741671c4B919523912fF
Arg [1] : asset_ (address): 0x336D414754967C6682B5A665C7DAF6F1409E63e8
Arg [2] : mm (address): 0x830D40CDFdc494BC1A2729a7381bfCe44326c944
Arg [3] : IRM_ (address): 0x5b1d3a91457f7AD854a559dAACc0be18cD402D12
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000001310f352f1389969ece6741671c4b919523912ff
Arg [1] : 000000000000000000000000336d414754967c6682b5a665c7daf6f1409e63e8
Arg [2] : 000000000000000000000000830d40cdfdc494bc1a2729a7381bfce44326c944
Arg [3] : 0000000000000000000000005b1d3a91457f7ad854a559daacc0be18cd402d12
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.