ERC-20
Overview
Max Total Supply
500.233722120308277496 rfETH
Holders
196,243
Total Transfers
-
Market
Price
$0.00 @ 0.000000 ETH
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Loading...
Loading
Loading...
Loading
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:
CEther
Compiler Version
v0.8.17+commit.8df45f5f
ZkSolc Version
v1.3.5
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "./CToken.sol"; /** * @title Compound's CEther Contract * @notice CToken which wraps Ether * @author Compound */ contract CEther is CToken { /** * @notice Construct a new CEther money market * @param comptroller_ The address of the Comptroller * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ ERC-20 name of this token * @param symbol_ ERC-20 symbol of this token * @param decimals_ ERC-20 decimal precision of this token * @param admin_ Address of the administrator of this token */ constructor( Comptroller comptroller_, InterestRateModel interestRateModel_, uint initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, address payable admin_, bytes32 pythId ) { // Creator of the contract is admin during initialization admin = payable(msg.sender); initialize( comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, pythId ); // Set the proper admin now that initialization is done admin = admin_; } /*** User Interface ***/ /** * @notice Sender supplies assets into the market and receives cTokens in exchange * @dev Reverts upon any failure */ function mint() external payable { mintInternal(msg.value); } /** * @notice Sender redeems cTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemTokens The number of cTokens to redeem into underlying * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeem(uint redeemTokens) external returns (uint) { redeemInternal(redeemTokens); return NO_ERROR; } /** * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemAmount The amount of underlying to redeem * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemUnderlying(uint redeemAmount) external returns (uint) { redeemUnderlyingInternal(redeemAmount); return NO_ERROR; } /** * @notice Sender borrows assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function borrow(uint borrowAmount) external returns (uint) { borrowInternal(borrowAmount); return NO_ERROR; } /** * @notice Sender repays their own borrow * @dev Reverts upon any failure */ function repayBorrow() external payable { repayBorrowInternal(msg.value); } /** * @notice Sender repays a borrow belonging to borrower * @dev Reverts upon any failure * @param borrower the account with the debt being payed off */ function repayBorrowBehalf(address borrower) external payable { repayBorrowBehalfInternal(borrower, msg.value); } /** * @notice The sender liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @dev Reverts upon any failure * @param borrower The borrower of this cToken to be liquidated * @param cTokenCollateral The market in which to seize collateral from the borrower */ function liquidateBorrow( address borrower, CToken cTokenCollateral ) external payable { liquidateBorrowInternal(borrower, msg.value, cTokenCollateral); } /** * @notice The sender adds to reserves. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _addReserves() external payable returns (uint) { return _addReservesInternal(msg.value); } /** * @notice Send Ether to CEther to mint */ receive() external payable { mintInternal(msg.value); } /*** Safe Token ***/ /** * @notice Gets balance of this contract in terms of Ether, before this message * @dev This excludes the value of the current message, if any * @return The quantity of Ether owned by this contract */ function getCashPrior() internal view override returns (uint) { return address(this).balance - msg.value; } /** * @notice Perform the actual transfer in, which is a no-op * @param from Address sending the Ether * @param amount Amount of Ether being sent * @return The actual amount of Ether transferred */ function doTransferIn( address from, uint amount ) internal override returns (uint) { // Sanity checks require(msg.sender == from, "sender mismatch"); require(msg.value == amount, "value mismatch"); return amount; } function doTransferOut( address payable to, uint amount ) internal virtual override { /* Send the Ether, with minimal gas and revert on failure */ (bool success, ) = to.call{value: amount}(""); require(success, "Failed to transfer ether"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ 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. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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 Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ 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); /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @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 places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ 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. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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 Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ 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); /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is 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 places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the 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. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "./CToken.sol"; interface CompLike { function delegate(address delegatee) external; } /** * @title Compound's CErc20 Contract * @notice CTokens which wrap an EIP-20 underlying * @author Compound */ contract CErc20 is CToken, CErc20Interface { /** * @notice Initialize the new money market * @param underlying_ The address of the underlying asset * @param comptroller_ The address of the Comptroller * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ ERC-20 name of this token * @param symbol_ ERC-20 symbol of this token * @param decimals_ ERC-20 decimal precision of this token */ function initialize( address underlying_, Comptroller comptroller_, InterestRateModel interestRateModel_, uint initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, bytes32 pythId ) public { // CToken initialize does the bulk of the work super.initialize( comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, pythId ); // Set underlying and sanity check it underlying = underlying_; EIP20Interface(underlying).totalSupply(); } /*** User Interface ***/ /** * @notice Sender supplies assets into the market and receives cTokens in exchange * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mintAmount The amount of the underlying asset to supply * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function mint(uint mintAmount) external override returns (uint) { mintInternal(mintAmount); return NO_ERROR; } /** * @notice Sender redeems cTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemTokens The number of cTokens to redeem into underlying * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeem(uint redeemTokens) external override returns (uint) { redeemInternal(redeemTokens); return NO_ERROR; } /** * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemAmount The amount of underlying to redeem * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemUnderlying( uint redeemAmount ) external override returns (uint) { redeemUnderlyingInternal(redeemAmount); return NO_ERROR; } /** * @notice Sender borrows assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function borrow(uint borrowAmount) external override returns (uint) { borrowInternal(borrowAmount); return NO_ERROR; } /** * @notice Sender repays their own borrow * @param repayAmount The amount to repay, or -1 for the full outstanding amount * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function repayBorrow(uint repayAmount) external override returns (uint) { repayBorrowInternal(repayAmount); return NO_ERROR; } /** * @notice Sender repays a borrow belonging to borrower * @param borrower the account with the debt being payed off * @param repayAmount The amount to repay, or -1 for the full outstanding amount * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function repayBorrowBehalf( address borrower, uint repayAmount ) external override returns (uint) { repayBorrowBehalfInternal(borrower, repayAmount); return NO_ERROR; } /** * @notice The sender liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param borrower The borrower of this cToken to be liquidated * @param repayAmount The amount of the underlying borrowed asset to repay * @param cTokenCollateral The market in which to seize collateral from the borrower * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function liquidateBorrow( address borrower, uint repayAmount, CTokenInterface cTokenCollateral ) external override returns (uint) { liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral); return NO_ERROR; } /** * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock) * @param token The address of the ERC-20 token to sweep */ function sweepToken(EIP20NonStandardInterface token) external override { require( msg.sender == admin, "CErc20::sweepToken: only admin can sweep tokens" ); require( address(token) != underlying, "CErc20::sweepToken: can not sweep underlying token" ); uint256 balance = token.balanceOf(address(this)); token.transfer(admin, balance); } /** * @notice The sender adds to reserves. * @param addAmount The amount fo underlying token to add as reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _addReserves(uint addAmount) external override returns (uint) { return _addReservesInternal(addAmount); } /*** Safe Token ***/ /** * @notice Gets balance of this contract in terms of the underlying * @dev This excludes the value of the current message, if any * @return The quantity of underlying tokens owned by this contract */ function getCashPrior() internal view virtual override returns (uint) { EIP20Interface token = EIP20Interface(underlying); return token.balanceOf(address(this)); } /** * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. * This will revert due to insufficient balance or insufficient allowance. * This function returns the actual amount received, * which may be less than `amount` if there is a fee attached to the transfer. * * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ function doTransferIn( address from, uint amount ) internal virtual override returns (uint) { // Read from storage once address underlying_ = underlying; EIP20NonStandardInterface token = EIP20NonStandardInterface( underlying_ ); uint balanceBefore = EIP20Interface(underlying_).balanceOf( address(this) ); token.transferFrom(from, address(this), amount); bool success; assembly { switch returndatasize() case 0 { // This is a non-standard ERC-20 success := not(0) // set success to true } case 32 { // This is a compliant ERC-20 returndatacopy(0, 0, 32) success := mload(0) // Set `success = returndata` of override external call } default { // This is an excessively non-compliant ERC-20, revert. revert(0, 0) } } require(success, "TOKEN_TRANSFER_IN_FAILED"); // Calculate the amount that was *actually* transferred uint balanceAfter = EIP20Interface(underlying_).balanceOf( address(this) ); return balanceAfter - balanceBefore; // underflow already checked above, just subtract } /** * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified * it is >= amount, this should not revert in normal conditions. * * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ function doTransferOut( address payable to, uint amount ) internal virtual override { EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); token.transfer(to, amount); bool success; assembly { switch returndatasize() case 0 { // This is a non-standard ERC-20 success := not(0) // set success to true } case 32 { // This is a compliant ERC-20 returndatacopy(0, 0, 32) success := mload(0) // Set `success = returndata` of override external call } default { // This is an excessively non-compliant ERC-20, revert. revert(0, 0) } } require(success, "TOKEN_TRANSFER_OUT_FAILED"); } }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./Comptroller.sol"; import "./CTokenInterfaces.sol"; import "./ErrorReporter.sol"; import "./EIP20Interface.sol"; import "./InterestRateModel.sol"; import "./ExponentialNoError.sol"; import "./es33/RewardDistributor.sol"; import "./lib/RPow.sol"; /** * @title Compound's CToken Contract * @notice Abstract base for CTokens * @author Compound */ abstract contract CToken is CTokenInterface, ExponentialNoError, TokenErrorReporter { /** * @notice Initialize the money market * @param comptroller_ The address of the Comptroller * @param interestRateModel_ The address of the interest rate model * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 * @param name_ EIP-20 name of this token * @param symbol_ EIP-20 symbol of this token * @param decimals_ EIP-20 decimal precision of this token */ function initialize( Comptroller comptroller_, InterestRateModel interestRateModel_, uint initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, bytes32 pythFeedID_ ) public { require(msg.sender == admin, "only admin may initialize the market"); require( accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once" ); // Set initial exchange rate initialExchangeRateMantissa = initialExchangeRateMantissa_; require( initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero." ); // Set the comptroller uint err = _setComptroller(comptroller_); require(err == NO_ERROR, "setting comptroller failed"); // Initialize block number and borrow index (block number mocks depend on comptroller being set) accrualBlockNumber = getBlockNumber(); borrowIndex = mantissaOne; // Set the interest rate model (depends on block number / borrow index) err = _setInterestRateModelFresh(interestRateModel_); require(err == NO_ERROR, "setting interest rate model failed"); name = name_; symbol = symbol_; decimals = decimals_; pythFeedID = pythFeedID_; // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund) _notEntered = true; } function updateDistributor(address payable dist_) external { if (msg.sender != admin) { revert SetPendingAdminOwnerCheck(); } dist = RewardDistributor(dist_); } /** * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` * @dev Called by both `transfer` and `transferFrom` internally * @param spender The address of the account performing the transfer * @param src The address of the source account * @param dst The address of the destination account * @param tokens The number of tokens to transfer * @return 0 if the transfer succeeded, else revert */ function transferTokens( address spender, address src, address dst, uint tokens ) internal returns (uint) { /* Fail if transfer not allowed */ uint allowed = comptroller.transferAllowed( address(this), src, dst, tokens ); if (allowed != 0) { revert TransferComptrollerRejection(allowed); } /* Do not allow self-transfers */ if (src == dst) { revert TransferNotAllowed(); } /* Get the allowance, infinite for the account owner */ uint startingAllowance = 0; if (spender == src) { startingAllowance = type(uint).max; } else { startingAllowance = transferAllowances[src][spender]; } /* Do the calculations, checking for {under,over}flow */ uint allowanceNew = startingAllowance - tokens; uint srcTokensNew = accountTokens[src] - tokens; uint dstTokensNew = accountTokens[dst] + tokens; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) accountTokens[src] = srcTokensNew; accountTokens[dst] = dstTokensNew; /* Eat some of the allowance (if necessary) */ if (startingAllowance != type(uint).max) { transferAllowances[src][spender] = allowanceNew; } dist.onAssetDecrease(bytes32("SUPPLY"), src, tokens); dist.onAssetIncrease(bytes32("SUPPLY"), dst, tokens); /* We emit a Transfer event */ emit Transfer(src, dst, tokens); comptroller.emitTransfer( src, dst, accountTokens[src], accountTokens[dst] ); // unused function // comptroller.transferVerify(address(this), src, dst, tokens); return NO_ERROR; } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer( address dst, uint256 amount ) external override nonReentrant returns (bool) { return transferTokens(msg.sender, msg.sender, dst, amount) == NO_ERROR; } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom( address src, address dst, uint256 amount ) external override nonReentrant returns (bool) { return transferTokens(msg.sender, src, dst, amount) == NO_ERROR; } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (uint256.max means infinite) * @return Whether or not the approval succeeded */ function approve( address spender, uint256 amount ) external override returns (bool) { address src = msg.sender; transferAllowances[src][spender] = amount; emit Approval(src, spender, amount); return true; } /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return The number of tokens allowed to be spent (-1 means infinite) */ function allowance( address owner, address spender ) external view override returns (uint256) { return transferAllowances[owner][spender]; } /** * @notice Get the token balance of the `owner` * @param owner The address of the account to query * @return The number of tokens owned by `owner` */ function balanceOf(address owner) external view override returns (uint256) { return accountTokens[owner]; } /** * @notice Get the underlying balance of the `owner` * @dev This also accrues interest in a transaction * @param owner The address of the account to query * @return The amount of underlying owned by `owner` */ function balanceOfUnderlying( address owner ) external override returns (uint) { Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); return mul_ScalarTruncate(exchangeRate, accountTokens[owner]); } /** * @notice Get a snapshot of the account's balances, and the cached exchange rate * @dev This is used by comptroller to more efficiently perform liquidity checks. * @param account Address of the account to snapshot * @return (possible error, token balance, borrow balance, exchange rate mantissa) */ function getAccountSnapshot( address account ) external view override returns (uint, uint, uint, uint) { return ( NO_ERROR, accountTokens[account], borrowBalanceStoredInternal(account), exchangeRateStoredInternal() ); } function getSnapshots( address[] calldata accounts ) external view returns (uint256[2][] memory) { uint256[2][] memory ret = new uint256[2][](accounts.length); for (uint256 i = 0; i < accounts.length; i++) { address acc = accounts[i]; ret[i][0] = accountTokens[acc]; ret[i][1] = accountBorrows[acc].interestIndex == 0 ? 0 : ((accountBorrows[acc].principal * 1e18) / accountBorrows[acc].interestIndex); } return ret; } function getStaticBalance( address acc ) external view returns (uint256, uint256) { return ( accountTokens[acc], accountBorrows[acc].interestIndex == 0 ? 0 : ((accountBorrows[acc].principal * 1e18) / accountBorrows[acc].interestIndex) ); } /** * @dev Function to simply retrieve block number * This exists mainly for inheriting test contracts to stub this result. */ function getBlockNumber() internal view virtual returns (uint) { return block.timestamp; } /** * @notice Returns the current per-block borrow interest rate for this cToken * @return The borrow interest rate per block, scaled by 1e18 */ function borrowRatePerBlock() external view override returns (uint) { return interestRateModel.getBorrowRate( getCashPrior(), totalBorrows, totalReserves ); } /** * @notice Returns the current per-block supply interest rate for this cToken * @return The supply interest rate per block, scaled by 1e18 */ function supplyRatePerBlock() external view override returns (uint) { return interestRateModel.getSupplyRate( getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa ); } /** * @notice Returns the current total borrows plus accrued interest * @return The total borrows with interest */ function totalBorrowsCurrent() external override nonReentrant returns (uint) { accrueInterest(); return totalBorrows; } /** * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex * @param account The address whose balance should be calculated after updating borrowIndex * @return The calculated balance */ function borrowBalanceCurrent( address account ) external override nonReentrant returns (uint) { accrueInterest(); return borrowBalanceStored(account); } /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @return The calculated balance */ function borrowBalanceStored( address account ) public view override returns (uint) { return borrowBalanceStoredInternal(account); } /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @return (error code, the calculated balance or 0 if error code is non-zero) */ function borrowBalanceStoredInternal( address account ) internal view returns (uint) { /* Get borrowBalance and borrowIndex */ BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; /* If borrowBalance = 0 then borrowIndex is likely also 0. * Rather than failing the calculation with a division by 0, we immediately return 0 in this case. */ if (borrowSnapshot.principal == 0) { return 0; } /* Calculate new borrow balance using the interest index: * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex */ uint principalTimesIndex = borrowSnapshot.principal * borrowIndex; return principalTimesIndex / borrowSnapshot.interestIndex; } /** * @notice Accrue interest then return the up-to-date exchange rate * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateCurrent() public override nonReentrant returns (uint) { accrueInterest(); return exchangeRateStored(); } /** * @notice Calculates the exchange rate from the underlying to the CToken * @dev This function does not accrue interest before calculating the exchange rate * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateStored() public view override returns (uint) { return exchangeRateStoredInternal(); } /** * @notice Calculates the exchange rate from the underlying to the CToken * @dev This function does not accrue interest before calculating the exchange rate * @return calculated exchange rate scaled by 1e18 */ function exchangeRateStoredInternal() internal view virtual returns (uint) { uint _totalSupply = totalSupply; if (_totalSupply == 0) { /* * If there are no tokens minted: * exchangeRate = initialExchangeRate */ return initialExchangeRateMantissa; } else { /* * Otherwise: * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint totalCash = getCashPrior(); uint cashPlusBorrowsMinusReserves = totalCash + totalBorrows - totalReserves; uint exchangeRate = (cashPlusBorrowsMinusReserves * expScale) / _totalSupply; return exchangeRate; } } /** * @notice Get cash balance of this cToken in the underlying asset * @return The quantity of underlying asset owned by this contract */ function getCash() external view override returns (uint) { return getCashPrior(); } /** * @notice Applies accrued interest to total borrows and reserves * @dev This calculates interest accrued from the last checkpointed block * up to the current block and writes new checkpoint to storage. */ function accrueInterest() public virtual override returns (uint) { /* Remember the initial block number */ uint currentBlockNumber = getBlockNumber(); uint accrualBlockNumberPrior = accrualBlockNumber; /* Short-circuit accumulating 0 interest */ if (accrualBlockNumberPrior == currentBlockNumber) { return NO_ERROR; } /* Read the previous values out of storage */ uint cashPrior = getCashPrior(); uint borrowsPrior = totalBorrows; uint reservesPrior = totalReserves; uint borrowIndexPrior = borrowIndex; /* Calculate the current borrow interest rate */ uint borrowRateMantissa = interestRateModel.getBorrowRate( cashPrior, borrowsPrior, reservesPrior ); require( borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high" ); /* Calculate the number of blocks elapsed since the last accrual */ uint blockDelta = currentBlockNumber - accrualBlockNumberPrior; /* * Calculate the interest accumulated into borrows and reserves and the new index: * simpleInterestFactor = (1 + borrowRate) ** blockDelta -- this is different from the original code (1.01 vs 0.01) * interestAccumulated = simpleInterestFactor * totalBorrows * totalBorrowsNew = interestAccumulated + totalBorrows * totalReservesNew = interestAccumulated * reserveFactor + totalReserves * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex */ uint256 simpleInterestFactor = RPow.rpow( 1e18 + borrowRateMantissa, blockDelta, 1e18 ); uint totalBorrowsNew = (simpleInterestFactor * borrowsPrior) / 1e18; uint interestAccumulated = totalBorrowsNew - borrowsPrior; uint totalReservesNew = reservesPrior + ((reserveFactorMantissa * interestAccumulated) / 1e18); uint borrowIndexNew = (simpleInterestFactor * borrowIndexPrior) / 1e18; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the previously calculated values into storage */ accrualBlockNumber = currentBlockNumber; borrowIndex = borrowIndexNew; totalBorrows = totalBorrowsNew; totalReserves = totalReservesNew; /* We emit an AccrueInterest event */ comptroller.emitAccrueInterest( interestAccumulated, borrowIndexNew, exchangeRateStoredInternal() ); return NO_ERROR; } /** * @notice Sender supplies assets into the market and receives cTokens in exchange * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mintAmount The amount of the underlying asset to supply */ function mintInternal(uint mintAmount) internal nonReentrant { accrueInterest(); // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to mintFresh(msg.sender, mintAmount); } /** * @notice User supplies assets into the market and receives cTokens in exchange * @dev Assumes interest has already been accrued up to the current block * @param minter The address of the account which is supplying the assets * @param mintAmount The amount of the underlying asset to supply */ function mintFresh(address minter, uint mintAmount) internal { /* Fail if mint not allowed */ uint allowed = comptroller.mintAllowed( address(this), minter, mintAmount ); if (allowed != 0) { revert MintComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert MintFreshnessCheck(); } Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()}); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call `doTransferIn` for the minter and the mintAmount. * Note: The cToken must handle variations between ERC-20 and ETH underlying. * `doTransferIn` reverts if anything goes wrong, since we can't be sure if * side-effects occurred. The function returns the amount actually transferred, * in case of a fee. On success, the cToken holds an additional `actualMintAmount` * of cash. */ uint actualMintAmount = doTransferIn(minter, mintAmount); /* * We get the current exchange rate and calculate the number of cTokens to be minted: * mintTokens = actualMintAmount / exchangeRate */ uint mintTokens = div_(actualMintAmount, exchangeRate); /* * We calculate the new total supply of cTokens and minter token balance, checking for overflow: * totalSupplyNew = totalSupply + mintTokens * accountTokensNew = accountTokens[minter] + mintTokens * And write them into storage */ totalSupply = totalSupply + mintTokens; accountTokens[minter] = accountTokens[minter] + mintTokens; dist.onAssetIncrease(bytes32("SUPPLY"), minter, mintTokens); /* We emit a Mint event, and a Transfer event */ emit Mint(minter, actualMintAmount, mintTokens); comptroller.emitMint(minter, actualMintAmount, mintTokens); emit Transfer(address(this), minter, mintTokens); comptroller.emitTransfer( address(this), minter, 0, accountTokens[minter] ); /* We call the defense hook */ // unused function // comptroller.mintVerify(address(this), minter, actualMintAmount, mintTokens); } event Mint(address minter, uint mintAmount, uint mintTokens); /** * @notice Event emitted when tokens are redeemed */ event Redeem(address redeemer, uint redeemAmount, uint redeemTokens); /** * @notice Sender redeems cTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemTokens The number of cTokens to redeem into underlying */ function redeemInternal(uint redeemTokens) internal nonReentrant { accrueInterest(); // redeemFresh emits redeem-specific logs on errors, so we don't need to redeemFresh(payable(msg.sender), redeemTokens, 0); } /** * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemAmount The amount of underlying to receive from redeeming cTokens */ function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant { accrueInterest(); // redeemFresh emits redeem-specific logs on errors, so we don't need to redeemFresh(payable(msg.sender), 0, redeemAmount); } /** * @notice User redeems cTokens in exchange for the underlying asset * @dev Assumes interest has already been accrued up to the current block * @param redeemer The address of the account which is redeeming the tokens * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero) * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero) */ function redeemFresh( address payable redeemer, uint redeemTokensIn, uint redeemAmountIn ) internal { require( redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero" ); /* exchangeRate = invoke Exchange Rate Stored() */ Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()}); uint redeemTokens; uint redeemAmount; /* If redeemTokensIn > 0: */ if (redeemTokensIn > 0) { /* * We calculate the exchange rate and the amount of underlying to be redeemed: * redeemTokens = redeemTokensIn * redeemAmount = redeemTokensIn x exchangeRateCurrent */ redeemTokens = redeemTokensIn; redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokensIn); } else { /* * We get the current exchange rate and calculate the amount to be redeemed: * redeemTokens = redeemAmountIn / exchangeRate * redeemAmount = redeemAmountIn */ redeemTokens = div_(redeemAmountIn, exchangeRate); redeemAmount = redeemAmountIn; } /* Fail if redeem not allowed */ uint allowed = comptroller.redeemAllowed( address(this), redeemer, redeemTokens ); if (allowed != 0) { revert RedeemComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert RedeemFreshnessCheck(); } /* Fail gracefully if protocol has insufficient cash */ if (getCashPrior() < redeemAmount) { revert RedeemTransferOutNotPossible(); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We write the previously calculated values into storage. * Note: Avoid token reentrancy attacks by writing reduced supply before external transfer. */ totalSupply = totalSupply - redeemTokens; accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens; /* * We invoke doTransferOut for the redeemer and the redeemAmount. * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken has redeemAmount less of cash. * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ doTransferOut(redeemer, redeemAmount); dist.onAssetDecrease(bytes32("SUPPLY"), redeemer, redeemTokens); /* We emit a Transfer event, and a Redeem event */ emit Transfer(redeemer, address(this), redeemTokens); comptroller.emitTransfer( redeemer, address(this), accountTokens[redeemer], 0 ); comptroller.emitRedeem(redeemer, redeemAmount, redeemTokens); emit Redeem(redeemer, redeemAmount, redeemTokens); /* We call the defense hook */ comptroller.redeemVerify( address(this), redeemer, redeemAmount, redeemTokens ); } /** * @notice Sender borrows assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow */ function borrowInternal(uint borrowAmount) internal nonReentrant { accrueInterest(); // borrowFresh emits borrow-specific logs on errors, so we don't need to borrowFresh(payable(msg.sender), borrowAmount); } /** * @notice Users borrow assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow */ function borrowFresh( address payable borrower, uint256 borrowAmount ) internal { /* Fail if borrow not allowed */ uint allowed = comptroller.borrowAllowed( address(this), borrower, borrowAmount ); if (allowed != 0) { revert BorrowComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert BorrowFreshnessCheck(); } /* Fail gracefully if protocol has insufficient underlying cash */ if (getCashPrior() < borrowAmount) { revert BorrowCashNotAvailable(); } /* * We calculate the new borrower and total borrow balances, failing on overflow: * accountBorrowNew = accountBorrow + borrowAmount * totalBorrowsNew = totalBorrows + borrowAmount */ uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower); uint accountBorrowsNew = accountBorrowsPrev + borrowAmount; uint totalBorrowsNew = totalBorrows + borrowAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We write the previously calculated values into storage. * Note: Avoid token reentrancy attacks by writing increased borrow before external transfer. `*/ accountBorrows[borrower].principal = accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = totalBorrowsNew; /* * We invoke doTransferOut for the borrower and the borrowAmount. * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken borrowAmount less of cash. * doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. */ doTransferOut(borrower, borrowAmount); dist.onAssetIncrease( bytes32("BORROW"), borrower, ((borrowAmount * 1e18) / borrowIndex) ); /* We emit a Borrow event */ comptroller.emitBorrow( borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew, (accountBorrowsNew * 1e18) / borrowIndex ); } /** * @notice Sender repays their own borrow * @param repayAmount The amount to repay, or -1 for the full outstanding amount */ function repayBorrowInternal(uint repayAmount) internal nonReentrant { accrueInterest(); // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to repayBorrowFresh(msg.sender, msg.sender, repayAmount); } /** * @notice Sender repays a borrow belonging to borrower * @param borrower the account with the debt being payed off * @param repayAmount The amount to repay, or -1 for the full outstanding amount */ function repayBorrowBehalfInternal( address borrower, uint repayAmount ) internal nonReentrant { accrueInterest(); // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to repayBorrowFresh(msg.sender, borrower, repayAmount); } /** * @notice Borrows are repaid by another user (possibly the borrower). * @param payer the account paying off the borrow * @param borrower the account with the debt being payed off * @param repayAmount the amount of underlying tokens being returned, or -1 for the full outstanding amount * @return (uint) the actual repayment amount. */ function repayBorrowFresh( address payer, address borrower, uint repayAmount ) internal returns (uint) { /* Fail if repayBorrow not allowed */ uint allowed = comptroller.repayBorrowAllowed( address(this), payer, borrower, repayAmount ); if (allowed != 0) { revert RepayBorrowComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert RepayBorrowFreshnessCheck(); } /* We fetch the amount the borrower owes, with accumulated interest */ uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower); /* If repayAmount == -1, repayAmount = accountBorrows */ uint repayAmountFinal = repayAmount == type(uint).max ? accountBorrowsPrev : repayAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call doTransferIn for the payer and the repayAmount * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken holds an additional repayAmount of cash. * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. * it returns the amount actually transferred, in case of a fee. */ uint actualRepayAmount = doTransferIn(payer, repayAmountFinal); /* * We calculate the new borrower and total borrow balances, failing on underflow: * accountBorrowsNew = accountBorrows - actualRepayAmount * totalBorrowsNew = totalBorrows - actualRepayAmount */ uint accountBorrowsNew = accountBorrowsPrev - actualRepayAmount; uint totalBorrowsNew = totalBorrows - actualRepayAmount; /* We write the previously calculated values into storage */ accountBorrows[borrower].principal = accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = totalBorrowsNew; dist.onAssetChange( bytes32("BORROW"), borrower, ((accountBorrowsNew * 1e18) / borrowIndex) ); /* We emit a RepayBorrow event */ comptroller.emitRepayBorrow( payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew, (accountBorrowsNew * 1e18) / borrowIndex ); return actualRepayAmount; } /** * @notice The sender liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param borrower The borrower of this cToken to be liquidated * @param cTokenCollateral The market in which to seize collateral from the borrower * @param repayAmount The amount of the underlying borrowed asset to repay */ function liquidateBorrowInternal( address borrower, uint repayAmount, CTokenInterface cTokenCollateral ) internal nonReentrant { accrueInterest(); uint error = cTokenCollateral.accrueInterest(); if (error != NO_ERROR) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed revert LiquidateAccrueCollateralInterestFailed(error); } // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to liquidateBorrowFresh( msg.sender, borrower, repayAmount, cTokenCollateral ); } /** * @notice The liquidator liquidates the borrowers collateral. * The collateral seized is transferred to the liquidator. * @param borrower The borrower of this cToken to be liquidated * @param liquidator The address repaying the borrow and seizing collateral * @param cTokenCollateral The market in which to seize collateral from the borrower * @param repayAmount The amount of the underlying borrowed asset to repay */ function liquidateBorrowFresh( address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral ) internal { /* Fail if liquidate not allowed */ uint allowed = comptroller.liquidateBorrowAllowed( address(this), address(cTokenCollateral), liquidator, borrower, repayAmount ); if (allowed != 0) { revert LiquidateComptrollerRejection(allowed); } /* Verify market's block number equals current block number */ if (accrualBlockNumber != getBlockNumber()) { revert LiquidateFreshnessCheck(); } /* Verify cTokenCollateral market's block number equals current block number */ if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { revert LiquidateCollateralFreshnessCheck(); } /* Fail if borrower = liquidator */ if (borrower == liquidator) { revert LiquidateLiquidatorIsBorrower(); } /* Fail if repayAmount = 0 */ if (repayAmount == 0) { revert LiquidateCloseAmountIsZero(); } /* Fail if repayAmount = -1 */ if (repayAmount == type(uint).max) { revert LiquidateCloseAmountIsUintMax(); } /* Fail if repayBorrow fails */ uint actualRepayAmount = repayBorrowFresh( liquidator, borrower, repayAmount ); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We calculate the number of collateral tokens that will be seized */ (uint amountSeizeError, uint seizeTokens) = comptroller .liquidateCalculateSeizeTokens( address(this), address(cTokenCollateral), actualRepayAmount ); require( amountSeizeError == NO_ERROR, "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED" ); /* Revert if borrower collateral token balance < seizeTokens */ require( cTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH" ); // If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call if (address(cTokenCollateral) == address(this)) { seizeInternal(address(this), liquidator, borrower, seizeTokens); } else { require( cTokenCollateral.seize(liquidator, borrower, seizeTokens) == NO_ERROR, "token seizure failed" ); } /* We emit a LiquidateBorrow event */ comptroller.emitLiquidateBorrow( liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens ); } /** * @notice Transfers collateral tokens (this market) to the liquidator. * @dev Will fail unless called by another cToken during the process of liquidation. * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. * @param liquidator The account receiving seized collateral * @param borrower The account having collateral seized * @param seizeTokens The number of cTokens to seize * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function seize( address liquidator, address borrower, uint seizeTokens ) external override nonReentrant returns (uint) { seizeInternal(msg.sender, liquidator, borrower, seizeTokens); return NO_ERROR; } /** * @notice Transfers collateral tokens (this market) to the liquidator. * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken. * Its absolutely critical to use msg.sender as the seizer cToken and not a parameter. * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken) * @param liquidator The account receiving seized collateral * @param borrower The account having collateral seized * @param seizeTokens The number of cTokens to seize */ function seizeInternal( address seizerToken, address liquidator, address borrower, uint seizeTokens ) internal { /* Fail if seize not allowed */ uint allowed = comptroller.seizeAllowed( address(this), seizerToken, liquidator, borrower, seizeTokens ); if (allowed != 0) { revert LiquidateSeizeComptrollerRejection(allowed); } /* Fail if borrower = liquidator */ if (borrower == liquidator) { revert LiquidateSeizeLiquidatorIsBorrower(); } /* * We calculate the new borrower and liquidator token balances, failing on underflow/overflow: * borrowerTokensNew = accountTokens[borrower] - seizeTokens * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens */ uint protocolSeizeTokens = mul_( seizeTokens, Exp({mantissa: protocolSeizeShareMantissa}) ); uint liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens; Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()}); uint protocolSeizeAmount = mul_ScalarTruncate( exchangeRate, protocolSeizeTokens ); uint totalReservesNew = totalReserves + protocolSeizeAmount; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the calculated values into storage */ totalReserves = totalReservesNew; totalSupply = totalSupply - protocolSeizeTokens; accountTokens[borrower] = accountTokens[borrower] - seizeTokens; accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens; dist.onAssetDecrease(bytes32("SUPPLY"), borrower, seizeTokens); dist.onAssetIncrease( bytes32("SUPPLY"), liquidator, liquidatorSeizeTokens ); /* Emit a Transfer event */ emit Transfer(borrower, liquidator, liquidatorSeizeTokens); comptroller.emitTransfer( borrower, liquidator, accountTokens[borrower], accountTokens[liquidator] ); emit Transfer(borrower, address(this), protocolSeizeTokens); emit ReservesAdded( address(this), protocolSeizeAmount, totalReservesNew ); } /*** Admin Functions ***/ /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setPendingAdmin( address payable newPendingAdmin ) external override returns (uint) { // Check caller = admin if (msg.sender != admin) { revert SetPendingAdminOwnerCheck(); } // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); return NO_ERROR; } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _acceptAdmin() external override returns (uint) { // Check caller is pendingAdmin and pendingAdmin ≠ address(0) if (msg.sender != pendingAdmin || msg.sender == address(0)) { revert AcceptAdminPendingAdminCheck(); } // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = payable(address(0)); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); return NO_ERROR; } /** * @notice Sets a new comptroller for the market * @dev Admin function to set a new comptroller * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setComptroller( Comptroller newComptroller ) public override returns (uint) { // Check caller is admin if (msg.sender != admin) { revert SetComptrollerOwnerCheck(); } Comptroller oldComptroller = comptroller; // Ensure invoke comptroller.isComptroller() returns true require(newComptroller.isComptroller(), "marker method returned false"); // Set market's comptroller to newComptroller comptroller = newComptroller; // Emit NewComptroller(oldComptroller, newComptroller) emit NewComptroller(oldComptroller, newComptroller); return NO_ERROR; } /** * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh * @dev Admin function to accrue interest and set a new reserve factor * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setReserveFactor( uint newReserveFactorMantissa ) external override nonReentrant returns (uint) { accrueInterest(); // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to. return _setReserveFactorFresh(newReserveFactorMantissa); } /** * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) * @dev Admin function to set a new reserve factor * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setReserveFactorFresh( uint newReserveFactorMantissa ) internal returns (uint) { // Check caller is admin if (msg.sender != admin) { revert SetReserveFactorAdminCheck(); } // Verify market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert SetReserveFactorFreshCheck(); } // Check newReserveFactor ≤ maxReserveFactor if (newReserveFactorMantissa > reserveFactorMaxMantissa) { revert SetReserveFactorBoundsCheck(); } uint oldReserveFactorMantissa = reserveFactorMantissa; reserveFactorMantissa = newReserveFactorMantissa; emit NewReserveFactor( oldReserveFactorMantissa, newReserveFactorMantissa ); return NO_ERROR; } /** * @notice Accrues interest and reduces reserves by transferring from msg.sender * @param addAmount Amount of addition to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _addReservesInternal( uint addAmount ) internal nonReentrant returns (uint) { accrueInterest(); // _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to. _addReservesFresh(addAmount); return NO_ERROR; } /** * @notice Add reserves by transferring from caller * @dev Requires fresh interest accrual * @param addAmount Amount of addition to reserves * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees */ function _addReservesFresh(uint addAmount) internal returns (uint, uint) { // totalReserves + actualAddAmount uint totalReservesNew; uint actualAddAmount; // We fail gracefully unless market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert AddReservesFactorFreshCheck(actualAddAmount); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* * We call doTransferIn for the caller and the addAmount * Note: The cToken must handle variations between ERC-20 and ETH underlying. * On success, the cToken holds an additional addAmount of cash. * doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred. * it returns the amount actually transferred, in case of a fee. */ actualAddAmount = doTransferIn(msg.sender, addAmount); totalReservesNew = totalReserves + actualAddAmount; // Store reserves[n+1] = reserves[n] + actualAddAmount totalReserves = totalReservesNew; /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */ emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew); /* Return (NO_ERROR, actualAddAmount) */ return (NO_ERROR, actualAddAmount); } function takeReserves() external returns (uint256) { // Check caller is admin or distributor if (msg.sender != admin && msg.sender != address(dist)) { revert ReduceReservesAdminCheck(); } // Store reserves[n+1] = reserves[n] - reduceAmount accrueInterest(); uint256 amount = totalReserves; totalReserves = 0; // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. doTransferOut(payable(address(dist)), amount); emit ReservesReduced(msg.sender, totalReserves, 0); } /** * @notice Accrues interest and reduces reserves by transferring to admin * @param reduceAmount Amount of reduction to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _reduceReserves( uint reduceAmount ) external override nonReentrant returns (uint) { accrueInterest(); // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to. return _reduceReservesFresh(reduceAmount); } /** * @notice Reduces reserves by transferring to admin * @dev Requires fresh interest accrual * @param reduceAmount Amount of reduction to reserves * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _reduceReservesFresh(uint reduceAmount) internal returns (uint) { // totalReserves - reduceAmount uint totalReservesNew; // Check caller is admin or distributor if (msg.sender != admin && msg.sender != address(dist)) { revert ReduceReservesAdminCheck(); } // We fail gracefully unless market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert ReduceReservesFreshCheck(); } // Fail gracefully if protocol has insufficient underlying cash if (getCashPrior() < reduceAmount) { revert ReduceReservesCashNotAvailable(); } // Check reduceAmount ≤ reserves[n] (totalReserves) if (reduceAmount > totalReserves) { revert ReduceReservesCashValidation(); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) totalReservesNew = totalReserves - reduceAmount; // Store reserves[n+1] = reserves[n] - reduceAmount totalReserves = totalReservesNew; // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred. doTransferOut(payable(address(dist)), reduceAmount); emit ReservesReduced(admin, reduceAmount, totalReservesNew); return NO_ERROR; } /** * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh * @dev Admin function to accrue interest and update the interest rate model * @param newInterestRateModel the new interest rate model to use * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setInterestRateModel( InterestRateModel newInterestRateModel ) public override returns (uint) { accrueInterest(); // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to. return _setInterestRateModelFresh(newInterestRateModel); } /** * @notice updates the interest rate model (*requires fresh interest accrual) * @dev Admin function to update the interest rate model * @param newInterestRateModel the new interest rate model to use * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setInterestRateModelFresh( InterestRateModel newInterestRateModel ) internal returns (uint) { // Used to store old model for use in the event that is emitted on success InterestRateModel oldInterestRateModel; // Check caller is admin if (msg.sender != admin) { revert SetInterestRateModelOwnerCheck(); } // We fail gracefully unless market's block number equals current block number if (accrualBlockNumber != getBlockNumber()) { revert SetInterestRateModelFreshCheck(); } // Track the market's current interest rate model oldInterestRateModel = interestRateModel; // Ensure invoke newInterestRateModel.isInterestRateModel() returns true require( newInterestRateModel.isInterestRateModel(), "marker method returned false" ); // Set the interest rate model to newInterestRateModel interestRateModel = newInterestRateModel; // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel) emit NewMarketInterestRateModel( oldInterestRateModel, newInterestRateModel ); return NO_ERROR; } /*** Safe Token ***/ /** * @notice Gets balance of this contract in terms of the underlying * @dev This excludes the value of the current message, if any * @return The quantity of underlying owned by this contract */ function getCashPrior() internal view virtual returns (uint); /** * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee. * This may revert due to insufficient balance or insufficient allowance. */ function doTransferIn( address from, uint amount ) internal virtual returns (uint); /** * @dev Performs a transfer out, ideally returning an explanatory error code upon failure rather than reverting. * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. */ function doTransferOut(address payable to, uint amount) internal virtual; /*** Reentrancy Guard ***/ /** * @dev Prevents a contract from calling itself, directly or indirectly. */ modifier nonReentrant() { require(_notEntered, "re-entered"); _notEntered = false; _; _notEntered = true; // get a gas-refund post-Istanbul } }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "./Comptroller.sol"; import "./InterestRateModel.sol"; import "./EIP20NonStandardInterface.sol"; import "./ErrorReporter.sol"; import "./es33/RewardDistributor.sol"; contract CTokenStorage { /** * @dev Guard variable for re-entrancy checks */ bool internal _notEntered; /** * @notice EIP-20 token name for this token */ string public name; /** * @notice EIP-20 token symbol for this token */ string public symbol; /** * @notice EIP-20 token decimals for this token */ uint8 public decimals; // Maximum borrow rate that can ever be applied (.0005% / block) uint internal constant borrowRateMaxMantissa = 0.0005e16; // Maximum fraction of interest that can be set aside for reserves uint internal constant reserveFactorMaxMantissa = 1e18; /** * @notice Administrator for this contract */ address payable public admin; /** * @notice Pending administrator for this contract */ address payable public pendingAdmin; /** * @notice Contract which oversees inter-cToken operations */ Comptroller public comptroller; /** * @notice Model which tells what the current interest rate should be */ InterestRateModel public interestRateModel; // Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) uint internal initialExchangeRateMantissa; /** * @notice Fraction of interest currently set aside for reserves */ uint public reserveFactorMantissa; /** * @notice Block number that interest was last accrued at */ uint public accrualBlockNumber; /** * @notice Accumulator of the total earned interest rate since the opening of the market */ uint public borrowIndex; /** * @notice Total amount of outstanding borrows of the underlying in this market */ uint256 public totalBorrows; /** * @notice Total amount of reserves of the underlying held in this market */ uint public totalReserves; /** * @notice Total number of tokens in circulation */ uint public totalSupply; // Official record of token balances for each account mapping(address => uint) internal accountTokens; // Approved token transfer amounts on behalf of others mapping(address => mapping(address => uint)) internal transferAllowances; /** * @notice Container for borrow balance information * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action * @member interestIndex Global borrowIndex as of the most recent balance-changing action */ struct BorrowSnapshot { uint principal; uint interestIndex; } // Mapping of account addresses to outstanding borrow balances mapping(address => BorrowSnapshot) internal accountBorrows; /** * @notice Share of seized collateral that is added to reserves */ uint public constant protocolSeizeShareMantissa = 2.8e16; //2.8% bytes32 public pythFeedID; RewardDistributor public dist; } abstract contract CTokenInterface is CTokenStorage { /** * @notice Indicator that this is a CToken contract (for inspection) */ bool public constant isCToken = true; /*** Market Events ***/ /*** Admin Events ***/ /** * @notice Event emitted when pendingAdmin is changed */ event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); /** * @notice Event emitted when pendingAdmin is accepted, which means admin is updated */ event NewAdmin(address oldAdmin, address newAdmin); /** * @notice Event emitted when comptroller is changed */ event NewComptroller( Comptroller oldComptroller, Comptroller newComptroller ); /** * @notice Event emitted when interestRateModel is changed */ event NewMarketInterestRateModel( InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel ); /** * @notice Event emitted when the reserve factor is changed */ event NewReserveFactor( uint oldReserveFactorMantissa, uint newReserveFactorMantissa ); /** * @notice Event emitted when the reserves are added */ event ReservesAdded( address benefactor, uint addAmount, uint newTotalReserves ); /** * @notice Event emitted when the reserves are reduced */ event ReservesReduced( address admin, uint reduceAmount, uint newTotalReserves ); /** * @notice EIP20 Transfer event */ event Transfer(address indexed from, address indexed to, uint amount); /** * @notice EIP20 Approval event */ event Approval(address indexed owner, address indexed spender, uint amount); /*** User Interface ***/ function transfer(address dst, uint amount) external virtual returns (bool); function transferFrom( address src, address dst, uint amount ) external virtual returns (bool); function approve( address spender, uint amount ) external virtual returns (bool); function allowance( address owner, address spender ) external view virtual returns (uint); function balanceOf(address owner) external view virtual returns (uint); function balanceOfUnderlying(address owner) external virtual returns (uint); function getAccountSnapshot( address account ) external view virtual returns (uint, uint, uint, uint); function borrowRatePerBlock() external view virtual returns (uint); function supplyRatePerBlock() external view virtual returns (uint); function totalBorrowsCurrent() external virtual returns (uint); function borrowBalanceCurrent( address account ) external virtual returns (uint); function borrowBalanceStored( address account ) external view virtual returns (uint); function exchangeRateCurrent() external virtual returns (uint); function exchangeRateStored() external view virtual returns (uint); function getCash() external view virtual returns (uint); function accrueInterest() external virtual returns (uint); function seize( address liquidator, address borrower, uint seizeTokens ) external virtual returns (uint); /*** Admin Functions ***/ function _setPendingAdmin( address payable newPendingAdmin ) external virtual returns (uint); function _acceptAdmin() external virtual returns (uint); function _setComptroller( Comptroller newComptroller ) external virtual returns (uint); function _setReserveFactor( uint newReserveFactorMantissa ) external virtual returns (uint); function _reduceReserves(uint reduceAmount) external virtual returns (uint); function _setInterestRateModel( InterestRateModel newInterestRateModel ) external virtual returns (uint); } contract CErc20Storage { /** * @notice Underlying asset for this CToken */ address public underlying; } abstract contract CErc20Interface is CErc20Storage { /*** User Interface ***/ function mint(uint mintAmount) external virtual returns (uint); function redeem(uint redeemTokens) external virtual returns (uint); function redeemUnderlying( uint redeemAmount ) external virtual returns (uint); function borrow(uint borrowAmount) external virtual returns (uint); function repayBorrow(uint repayAmount) external virtual returns (uint); function repayBorrowBehalf( address borrower, uint repayAmount ) external virtual returns (uint); function liquidateBorrow( address borrower, uint repayAmount, CTokenInterface cTokenCollateral ) external virtual returns (uint); function sweepToken(EIP20NonStandardInterface token) external virtual; /*** Admin Functions ***/ function _addReserves(uint addAmount) external virtual returns (uint); } contract CDelegationStorage { /** * @notice Implementation address for this contract */ address public implementation; } abstract contract CDelegatorInterface is CDelegationStorage { /** * @notice Emitted when implementation is changed */ event NewImplementation( address oldImplementation, address newImplementation ); /** * @notice Called by the admin to update the implementation of the delegator * @param implementation_ The address of the new implementation for delegation * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation */ function _setImplementation( address implementation_, bool allowResign, bytes memory becomeImplementationData ) external virtual; } abstract contract CDelegateInterface is CDelegationStorage { /** * @notice Called by the delegator on a delegate to initialize it for duty * @dev Should revert if any issues arise which make it unfit for delegation * @param data The encoded bytes data for any initialization */ function _becomeImplementation(bytes memory data) external virtual; /** * @notice Called by the delegator on a delegate to forfeit its responsibility */ function _resignImplementation() external virtual; }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./CToken.sol"; import "./ErrorReporter.sol"; import "./PriceOracle.sol"; import "./Comptroller.sol"; import "./ComptrollerStorage.sol"; import "./Unitroller.sol"; import "./ExponentialNoError.sol"; /** * @title Compound's Comptroller Contract * @author Compound */ contract Comptroller is ComptrollerV7Storage, ComptrollerErrorReporter, ExponentialNoError { bool public constant isComptroller = true; /// @notice Emitted when an admin supports a market event MarketListed(CToken cToken); /// @notice Emitted when an account enters a market event MarketEntered(CToken cToken, address account); /// @notice Emitted when an account exits a market event MarketExited(CToken cToken, address account); /// @notice Emitted when close factor is changed by admin event NewCloseFactor( uint oldCloseFactorMantissa, uint newCloseFactorMantissa ); /// @notice Emitted when a collateral factor is changed by admin event NewCollateralFactor( CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa ); /// @notice Emitted when liquidation incentive is changed by admin event NewLiquidationIncentive( uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa ); /// @notice Emitted when price oracle is changed event NewPriceOracle( PriceOracle oldPriceOracle, PriceOracle newPriceOracle ); /// @notice Emitted when pause guardian is changed event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); /// @notice Emitted when an action is paused globally event ActionPaused(string action, bool pauseState); /// @notice Emitted when an action is paused on a market event ActionPaused(CToken cToken, string action, bool pauseState); /// @notice Emitted when a new borrow-side COMP speed is calculated for a market event CompBorrowSpeedUpdated(CToken indexed cToken, uint newSpeed); /// @notice Emitted when a new supply-side COMP speed is calculated for a market event CompSupplySpeedUpdated(CToken indexed cToken, uint newSpeed); /// @notice Emitted when a new COMP speed is set for a contributor event ContributorCompSpeedUpdated( address indexed contributor, uint newSpeed ); /// @notice Emitted when COMP is distributed to a supplier event DistributedSupplierComp( CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex ); /// @notice Emitted when COMP is distributed to a borrower event DistributedBorrowerComp( CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex ); /// @notice Emitted when borrow cap for a cToken is changed event NewBorrowCap(CToken indexed cToken, uint newBorrowCap); /// @notice Emitted when borrow cap guardian is changed event NewBorrowCapGuardian( address oldBorrowCapGuardian, address newBorrowCapGuardian ); /// @notice The initial COMP index for a market uint224 public constant compInitialIndex = 1e36; // closeFactorMantissa must be strictly greater than this value uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05 // closeFactorMantissa must not exceed this value uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 // No collateralFactorMantissa may exceed this value uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9 constructor() { admin = msg.sender; } /*** Assets You Are In ***/ /** * @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 the account has entered */ function getAssetsIn( address account ) external view returns (CToken[] memory) { CToken[] memory assetsIn = accountAssets[account]; return assetsIn; } /** * @notice Returns whether the given account is entered in the given asset * @param account The address of the account to check * @param cToken The cToken to check * @return True if the account is in the asset, otherwise false. */ function checkMembership( address account, CToken cToken ) external view returns (bool) { return markets[address(cToken)].accountMembership[account]; } /** * @notice Add assets to be included in account liquidity calculation * @param cTokens The list of addresses of the cToken markets to be enabled * @return Success indicator for whether each corresponding market was entered */ function enterMarkets( address[] memory cTokens ) public returns (uint[] memory) { uint len = cTokens.length; uint[] memory results = new uint[](len); for (uint i = 0; i < len; i++) { CToken cToken = CToken(cTokens[i]); results[i] = uint(addToMarketInternal(cToken, msg.sender)); } return results; } /** * @notice Add the market to the borrower's "assets in" for liquidity calculations * @param cToken The market to enter * @param borrower The address of the account to modify * @return Success indicator for whether the market was entered */ function addToMarketInternal( CToken cToken, address borrower ) internal returns (Error) { Market storage marketToJoin = markets[address(cToken)]; if (!marketToJoin.isListed) { // market is not listed, cannot join return Error.MARKET_NOT_LISTED; } if (marketToJoin.accountMembership[borrower] == true) { // already joined return Error.NO_ERROR; } // survived the gauntlet, add to list // NOTE: we store these somewhat redundantly as a significant optimization // this avoids having to iterate through the list for the most common use cases // that is, only when we need to perform liquidity checks // and not whenever we want to check if an account is in a particular market marketToJoin.accountMembership[borrower] = true; accountAssets[borrower].push(cToken); emit MarketEntered(cToken, borrower); return Error.NO_ERROR; } /** * @notice Removes asset from sender's account liquidity calculation * @dev Sender must not have an outstanding borrow balance in the asset, * or be providing necessary collateral for an outstanding borrow. * @param cTokenAddress The address of the asset to be removed * @return Whether or not the account successfully exited the market */ function exitMarket(address cTokenAddress) external returns (uint) { CToken cToken = CToken(cTokenAddress); /* Get sender tokensHeld and amountOwed underlying from the cToken */ (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken .getAccountSnapshot(msg.sender); require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code /* Fail if the sender has a borrow balance */ if (amountOwed != 0) { return fail( Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED ); } /* Fail if the sender is not permitted to redeem all of their tokens */ uint allowed = redeemAllowedInternal( cTokenAddress, msg.sender, tokensHeld ); if (allowed != 0) { return failOpaque( Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed ); } Market storage marketToExit = markets[address(cToken)]; /* Return true if the sender is not already ‘in’ the market */ if (!marketToExit.accountMembership[msg.sender]) { return uint(Error.NO_ERROR); } /* Set cToken account membership to false */ delete marketToExit.accountMembership[msg.sender]; /* Delete cToken from the account’s list of assets */ // load into memory for faster iteration CToken[] memory userAssetList = accountAssets[msg.sender]; uint len = userAssetList.length; uint assetIndex = len; for (uint i = 0; i < len; i++) { if (userAssetList[i] == cToken) { assetIndex = i; break; } } // We *must* have found the asset in the list or our redundant data structure is broken assert(assetIndex < len); // copy last item in list to location of item to be removed, reduce length by 1 CToken[] storage storedList = accountAssets[msg.sender]; storedList[assetIndex] = storedList[storedList.length - 1]; storedList.pop(); emit MarketExited(cToken, msg.sender); return uint(Error.NO_ERROR); } /*** Policy Hooks ***/ /** * @notice Checks if the account should be allowed to mint tokens in the given market * @param cToken The market to verify the mint against * @param minter The account which would get the minted tokens * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function mintAllowed( address cToken, address minter, uint mintAmount ) external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!mintGuardianPaused[cToken], "mint is paused"); // Shh - currently unused minter; mintAmount; if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } return uint(Error.NO_ERROR); } /** * @notice Validates mint and reverts on rejection. May emit logs. * @param cToken Asset being minted * @param minter The address minting the tokens * @param actualMintAmount The amount of the underlying asset being minted * @param mintTokens The number of tokens being minted */ function mintVerify( address cToken, address minter, uint actualMintAmount, uint mintTokens ) external { // Shh - currently unused cToken; minter; actualMintAmount; mintTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the account should be allowed to redeem tokens in the given market * @param cToken The market to verify the redeem against * @param redeemer The account which would redeem the tokens * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function redeemAllowed( address cToken, address redeemer, uint redeemTokens ) external returns (uint) { uint allowed = redeemAllowedInternal(cToken, redeemer, redeemTokens); if (allowed != uint(Error.NO_ERROR)) { return allowed; } // Keep the flywheel moving return uint(Error.NO_ERROR); } function redeemAllowedInternal( address cToken, address redeemer, uint redeemTokens ) internal view returns (uint) { if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ if (!markets[cToken].accountMembership[redeemer]) { return uint(Error.NO_ERROR); } /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal( redeemer, CToken(cToken), redeemTokens, 0 ); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall > 0) { return uint(Error.INSUFFICIENT_LIQUIDITY); } return uint(Error.NO_ERROR); } /** * @notice Validates redeem and reverts on rejection. May emit logs. * @param cToken Asset being redeemed * @param redeemer The address redeeming the tokens * @param redeemAmount The amount of the underlying asset being redeemed * @param redeemTokens The number of tokens being redeemed */ function redeemVerify( address cToken, address redeemer, uint redeemAmount, uint redeemTokens ) external { // Shh - currently unused cToken; redeemer; // Require tokens is zero or amount is also zero if (redeemTokens == 0 && redeemAmount > 0) { revert("redeemTokens zero"); } } /** * @notice Checks if the account should be allowed to borrow the underlying asset of the given market * @param cToken The market to verify the borrow against * @param borrower The account which would borrow the asset * @param borrowAmount The amount of underlying the account would borrow * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function borrowAllowed( address cToken, address borrower, uint borrowAmount ) external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!borrowGuardianPaused[cToken], "borrow is paused"); if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } if (!markets[cToken].accountMembership[borrower]) { // only cTokens may call borrowAllowed if borrower not in market require(msg.sender == cToken, "sender must be cToken"); // attempt to add borrower to the market Error err = addToMarketInternal(CToken(msg.sender), borrower); if (err != Error.NO_ERROR) { return uint(err); } // it should be impossible to break the important invariant assert(markets[cToken].accountMembership[borrower]); } if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { return uint(Error.PRICE_ERROR); } uint borrowCap = borrowCaps[cToken]; // Borrow cap of 0 corresponds to unlimited borrowing if (borrowCap != 0) { uint totalBorrows = CToken(cToken).totalBorrows(); uint nextTotalBorrows = add_(totalBorrows, borrowAmount); require(nextTotalBorrows < borrowCap, "market borrow cap reached"); } (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal( borrower, CToken(cToken), 0, borrowAmount ); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall > 0) { return uint(Error.INSUFFICIENT_LIQUIDITY); } // Keep the flywheel moving return uint(Error.NO_ERROR); } /** * @notice Validates borrow and reverts on rejection. May emit logs. * @param cToken Asset whose underlying is being borrowed * @param borrower The address borrowing the underlying * @param borrowAmount The amount of the underlying asset requested to borrow */ function borrowVerify( address cToken, address borrower, uint borrowAmount ) external { // Shh - currently unused cToken; borrower; borrowAmount; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the account should be allowed to repay a borrow in the given market * @param cToken The market to verify the repay against * @param payer The account which would repay the asset * @param borrower The account which would borrowed the asset * @param repayAmount The amount of the underlying asset the account would repay * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function repayBorrowAllowed( address cToken, address payer, address borrower, uint repayAmount ) external returns (uint) { // Shh - currently unused payer; borrower; repayAmount; if (!markets[cToken].isListed) { return uint(Error.MARKET_NOT_LISTED); } return uint(Error.NO_ERROR); } /** * @notice Validates repayBorrow and reverts on rejection. May emit logs. * @param cToken Asset being repaid * @param payer The address repaying the borrow * @param borrower The address of the borrower * @param actualRepayAmount The amount of underlying being repaid */ function repayBorrowVerify( address cToken, address payer, address borrower, uint actualRepayAmount, uint borrowerIndex ) external { // Shh - currently unused cToken; payer; borrower; actualRepayAmount; borrowerIndex; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } function whitelistLiquidator(address a) external { require(msg.sender == admin, "unauthorized"); whitelistedLiquidator = a; } /** * @notice Checks if the liquidation should be allowed to occur * @param cTokenBorrowed Asset which was borrowed by the borrower * @param cTokenCollateral Asset which was used as collateral and will be seized * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param repayAmount The amount of underlying being repaid */ function liquidateBorrowAllowed( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint repayAmount ) external returns (uint) { // Shh - currently unused if (whitelistedLiquidator != address(0)) { require(liquidator == whitelistedLiquidator, "not whitelisted"); } if ( !markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed ) { return uint(Error.MARKET_NOT_LISTED); } uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored( borrower ); /* allow accounts to be liquidated if the market is deprecated */ if (isDeprecated(CToken(cTokenBorrowed))) { require( borrowBalance >= repayAmount, "Can not repay more than the total borrow" ); } else { /* The borrower must have shortfall in order to be liquidatable */ (Error err, , uint shortfall) = getAccountLiquidityInternal( borrower ); if (err != Error.NO_ERROR) { return uint(err); } if (shortfall == 0) { return uint(Error.INSUFFICIENT_SHORTFALL); } /* The liquidator may not repay more than what is allowed by the closeFactor */ uint maxClose = mul_ScalarTruncate( Exp({mantissa: closeFactorMantissa}), borrowBalance ); if (repayAmount > maxClose) { return uint(Error.TOO_MUCH_REPAY); } } return uint(Error.NO_ERROR); } /** * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. * @param cTokenBorrowed Asset which was borrowed by the borrower * @param cTokenCollateral Asset which was used as collateral and will be seized * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param actualRepayAmount The amount of underlying being repaid */ function liquidateBorrowVerify( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint actualRepayAmount, uint seizeTokens ) external { // Shh - currently unused cTokenBorrowed; cTokenCollateral; liquidator; borrower; actualRepayAmount; seizeTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the seizing of assets should be allowed to occur * @param cTokenCollateral Asset which was used as collateral and will be seized * @param cTokenBorrowed Asset which was borrowed by the borrower * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param seizeTokens The number of collateral tokens to seize */ function seizeAllowed( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens ) external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!seizeGuardianPaused, "seize is paused"); // Shh - currently unused seizeTokens; if ( !markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed ) { return uint(Error.MARKET_NOT_LISTED); } if ( CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller() ) { return uint(Error.COMPTROLLER_MISMATCH); } return uint(Error.NO_ERROR); } /** * @notice Validates seize and reverts on rejection. May emit logs. * @param cTokenCollateral Asset which was used as collateral and will be seized * @param cTokenBorrowed Asset which was borrowed by the borrower * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param seizeTokens The number of collateral tokens to seize */ function seizeVerify( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens ) external { // Shh - currently unused cTokenCollateral; cTokenBorrowed; liquidator; borrower; seizeTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /** * @notice Checks if the account should be allowed to transfer tokens in the given market * @param cToken The market to verify the transfer against * @param src The account which sources the tokens * @param dst The account which receives the tokens * @param transferTokens The number of cTokens to transfer * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) */ function transferAllowed( address cToken, address src, address dst, uint transferTokens ) external returns (uint) { // Pausing is a very serious situation - we revert to sound the alarms require(!transferGuardianPaused, "transfer is paused"); // Currently the only consideration is whether or not // the src is allowed to redeem this many tokens uint allowed = redeemAllowedInternal(cToken, src, transferTokens); if (allowed != uint(Error.NO_ERROR)) { return allowed; } return uint(Error.NO_ERROR); } /** * @notice Validates transfer and reverts on rejection. May emit logs. * @param cToken Asset being transferred * @param src The account which sources the tokens * @param dst The account which receives the tokens * @param transferTokens The number of cTokens to transfer */ function transferVerify( address cToken, address src, address dst, uint transferTokens ) external { // Shh - currently unused cToken; src; dst; transferTokens; // Shh - we don't ever want this hook to be marked pure if (false) { maxAssets = maxAssets; } } /*** Liquidity/Liquidation Calculations ***/ /** * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. * Note that `cTokenBalance` is the number of cTokens the account owns in the market, * whereas `borrowBalance` is the amount of underlying that the account has borrowed. */ struct AccountLiquidityLocalVars { uint sumCollateral; uint sumBorrowPlusEffects; uint cTokenBalance; uint borrowBalance; uint exchangeRateMantissa; uint oraclePriceMantissa; Exp collateralFactor; Exp exchangeRate; Exp oraclePrice; Exp tokensToDenom; } /** * @notice Determine the current account liquidity wrt collateral requirements * @return (possible error code (semi-opaque), account liquidity in excess of collateral requirements, * account shortfall below collateral requirements) */ function getAccountLiquidity( address account ) public view returns (uint, uint, uint) { ( Error err, uint liquidity, uint shortfall ) = getHypotheticalAccountLiquidityInternal( account, CToken(address(0)), 0, 0 ); return (uint(err), liquidity, shortfall); } /** * @notice Determine the current account liquidity wrt collateral requirements * @return (possible error code, account liquidity in excess of collateral requirements, * account shortfall below collateral requirements) */ function getAccountLiquidityInternal( address account ) internal view returns (Error, uint, uint) { return getHypotheticalAccountLiquidityInternal( account, CToken(address(0)), 0, 0 ); } /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param cTokenModify The market to hypothetically redeem/borrow in * @param account The account to determine liquidity for * @param redeemTokens The number of tokens to hypothetically redeem * @param borrowAmount The amount of underlying to hypothetically borrow * @return (possible error code (semi-opaque), hypothetical account liquidity in excess of collateral requirements, * hypothetical account shortfall below collateral requirements) */ function getHypotheticalAccountLiquidity( address account, address cTokenModify, uint redeemTokens, uint borrowAmount ) public view returns (uint, uint, uint) { ( Error err, uint liquidity, uint shortfall ) = getHypotheticalAccountLiquidityInternal( account, CToken(cTokenModify), redeemTokens, borrowAmount ); return (uint(err), liquidity, shortfall); } /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param cTokenModify The market to hypothetically redeem/borrow in * @param account The account to determine liquidity for * @param redeemTokens The number of tokens to hypothetically redeem * @param borrowAmount The amount of underlying to hypothetically borrow * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, * without calculating accumulated interest. * @return (possible error code, hypothetical account liquidity in excess of collateral requirements, * hypothetical account shortfall below collateral requirements) */ function getHypotheticalAccountLiquidityInternal( address account, CToken cTokenModify, uint redeemTokens, uint borrowAmount ) internal view returns (Error, uint, uint) { AccountLiquidityLocalVars memory vars; // Holds all our calculation results uint oErr; // For each asset the account is in CToken[] memory assets = accountAssets[account]; for (uint i = 0; i < assets.length; i++) { CToken asset = assets[i]; // Read the balances and exchange rate from the cToken ( oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa ) = asset.getAccountSnapshot(account); if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades return (Error.SNAPSHOT_ERROR, 0, 0); } vars.collateralFactor = Exp({ mantissa: markets[address(asset)].collateralFactorMantissa }); vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); // Get the normalized price of the asset vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); if (vars.oraclePriceMantissa == 0) { return (Error.PRICE_ERROR, 0, 0); } vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); // Pre-compute a conversion factor from tokens -> ether (normalized price value) vars.tokensToDenom = mul_( mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice ); // sumCollateral += tokensToDenom * cTokenBalance vars.sumCollateral = mul_ScalarTruncateAddUInt( vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral ); // sumBorrowPlusEffects += oraclePrice * borrowBalance vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects ); // Calculate effects of interacting with cTokenModify if (asset == cTokenModify) { // redeem effect // sumBorrowPlusEffects += tokensToDenom * redeemTokens vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects ); // borrow effect // sumBorrowPlusEffects += oraclePrice * borrowAmount vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects ); } } // These are safe, as the underflow condition is checked first if (vars.sumCollateral > vars.sumBorrowPlusEffects) { return ( Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0 ); } else { return ( Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral ); } } /** * @notice Calculate number of tokens of collateral asset to seize given an underlying amount * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) * @param cTokenBorrowed The address of the borrowed cToken * @param cTokenCollateral The address of the collateral cToken * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) */ function liquidateCalculateSeizeTokens( address cTokenBorrowed, address cTokenCollateral, uint actualRepayAmount ) external view returns (uint, uint) { /* Read oracle prices for borrowed and collateral markets */ uint priceBorrowedMantissa = oracle.getUnderlyingPrice( CToken(cTokenBorrowed) ); uint priceCollateralMantissa = oracle.getUnderlyingPrice( CToken(cTokenCollateral) ); if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { return (uint(Error.PRICE_ERROR), 0); } /* * Get the exchange rate and calculate the number of collateral tokens to seize: * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral * seizeTokens = seizeAmount / exchangeRate * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) */ uint exchangeRateMantissa = CToken(cTokenCollateral) .exchangeRateStored(); // Note: reverts on error uint seizeTokens; Exp memory numerator; Exp memory denominator; Exp memory ratio; numerator = mul_( Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa}) ); denominator = mul_( Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa}) ); ratio = div_(numerator, denominator); seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount); return (uint(Error.NO_ERROR), seizeTokens); } /*** Admin Functions ***/ /** * @notice Sets a new price oracle for the comptroller * @dev Admin function to set a new price oracle * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setPriceOracle(PriceOracle newOracle) public returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail( Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK ); } // Track the old oracle for the comptroller PriceOracle oldOracle = oracle; // Set comptroller's oracle to newOracle oracle = newOracle; // Emit NewPriceOracle(oldOracle, newOracle) emit NewPriceOracle(oldOracle, newOracle); return uint(Error.NO_ERROR); } /** * @notice Sets the closeFactor used when liquidating borrows * @dev Admin function to set closeFactor * @param newCloseFactorMantissa New close factor, scaled by 1e18 * @return uint 0=success, otherwise a failure */ function _setCloseFactor( uint newCloseFactorMantissa ) external returns (uint) { // Check caller is admin require(msg.sender == admin, "only admin can set close factor"); uint oldCloseFactorMantissa = closeFactorMantissa; closeFactorMantissa = newCloseFactorMantissa; emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); return uint(Error.NO_ERROR); } /** * @notice Sets the collateralFactor for a market * @dev Admin function to set per-market collateralFactor * @param cToken The market to set the factor on * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) */ function _setCollateralFactor( CToken cToken, uint newCollateralFactorMantissa ) external returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail( Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK ); } // Verify market is listed Market storage market = markets[address(cToken)]; if (!market.isListed) { return fail( Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS ); } Exp memory newCollateralFactorExp = Exp({ mantissa: newCollateralFactorMantissa }); // Check collateral factor <= 0.9 Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); if (lessThanExp(highLimit, newCollateralFactorExp)) { return fail( Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION ); } /* // If collateral factor != 0, fail if price == 0 if ( newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0 ) { return fail( Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE ); } */ // Set market's collateral factor to new collateral factor, remember old value uint oldCollateralFactorMantissa = market.collateralFactorMantissa; market.collateralFactorMantissa = newCollateralFactorMantissa; // Emit event with asset, old collateral factor, and new collateral factor emit NewCollateralFactor( cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa ); return uint(Error.NO_ERROR); } /** * @notice Sets liquidationIncentive * @dev Admin function to set liquidationIncentive * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) */ function _setLiquidationIncentive( uint newLiquidationIncentiveMantissa ) external returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail( Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK ); } // Save current value for use in log uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; // Set liquidation incentive to new incentive liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; // Emit event with old incentive, new incentive emit NewLiquidationIncentive( oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa ); return uint(Error.NO_ERROR); } /** * @notice Add the market to the markets mapping and set it as listed * @dev Admin function to set isListed and add support for the market * @param cToken The address of the market (token) to list * @return uint 0=success, otherwise a failure. (See enum Error for details) */ function _supportMarket(CToken cToken) external returns (uint) { if (msg.sender != admin) { return fail( Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK ); } if (markets[address(cToken)].isListed) { return fail( Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS ); } cToken.isCToken(); // Sanity check to make sure its really a CToken // Note that isComped is not in active use anymore Market storage newMarket = markets[address(cToken)]; newMarket.isListed = true; newMarket.collateralFactorMantissa = 0; _addMarketInternal(address(cToken)); emit MarketListed(cToken); return uint(Error.NO_ERROR); } function _addMarketInternal(address cToken) internal { for (uint i = 0; i < allMarkets.length; i++) { require(allMarkets[i] != CToken(cToken), "market already added"); } allMarkets.push(CToken(cToken)); } /** * @notice Set the given borrow caps for the given cToken markets. Borrowing that brings total borrows to or above borrow cap will revert. * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing. * @param cTokens The addresses of the markets (tokens) to change the borrow caps for * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing. */ function _setMarketBorrowCaps( CToken[] calldata cTokens, uint[] calldata newBorrowCaps ) external { require( msg.sender == admin || msg.sender == borrowCapGuardian, "only admin or borrow cap guardian can set borrow caps" ); uint numMarkets = cTokens.length; uint numBorrowCaps = newBorrowCaps.length; require( numMarkets != 0 && numMarkets == numBorrowCaps, "invalid input" ); for (uint i = 0; i < numMarkets; i++) { borrowCaps[address(cTokens[i])] = newBorrowCaps[i]; emit NewBorrowCap(cTokens[i], newBorrowCaps[i]); } } /** * @notice Admin function to change the Borrow Cap Guardian * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian */ function _setBorrowCapGuardian(address newBorrowCapGuardian) external { require(msg.sender == admin, "only admin can set borrow cap guardian"); // Save current value for inclusion in log address oldBorrowCapGuardian = borrowCapGuardian; // Store borrowCapGuardian with value newBorrowCapGuardian borrowCapGuardian = newBorrowCapGuardian; // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian) emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian); } /** * @notice Admin function to change the Pause Guardian * @param newPauseGuardian The address of the new Pause Guardian * @return uint 0=success, otherwise a failure. (See enum Error for details) */ function _setPauseGuardian(address newPauseGuardian) public returns (uint) { if (msg.sender != admin) { return fail( Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK ); } // Save current value for inclusion in log address oldPauseGuardian = pauseGuardian; // Store pauseGuardian with value newPauseGuardian pauseGuardian = newPauseGuardian; // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) emit NewPauseGuardian(oldPauseGuardian, pauseGuardian); return uint(Error.NO_ERROR); } function _setMintPaused(CToken cToken, bool state) public returns (bool) { require( markets[address(cToken)].isListed, "cannot pause a market that is not listed" ); require( msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause" ); require(msg.sender == admin || state == true, "only admin can unpause"); mintGuardianPaused[address(cToken)] = state; emit ActionPaused(cToken, "Mint", state); return state; } function _setBorrowPaused(CToken cToken, bool state) public returns (bool) { require( markets[address(cToken)].isListed, "cannot pause a market that is not listed" ); require( msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause" ); require(msg.sender == admin || state == true, "only admin can unpause"); borrowGuardianPaused[address(cToken)] = state; emit ActionPaused(cToken, "Borrow", state); return state; } function _setTransferPaused(bool state) public returns (bool) { require( msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause" ); require(msg.sender == admin || state == true, "only admin can unpause"); transferGuardianPaused = state; emit ActionPaused("Transfer", state); return state; } function _setSeizePaused(bool state) public returns (bool) { require( msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause" ); require(msg.sender == admin || state == true, "only admin can unpause"); seizeGuardianPaused = state; emit ActionPaused("Seize", state); return state; } function _become(Unitroller unitroller) public { require( msg.sender == unitroller.admin(), "only unitroller admin can change brains" ); require( unitroller._acceptImplementation() == 0, "change not authorized" ); } /** * @notice Return all of the markets * @dev The automatic getter may be used to access an individual market. * @return The list of market addresses */ function getAllMarkets() public view returns (CToken[] memory) { return allMarkets; } /** * @notice Return all of the markets * @dev The automatic getter may be used to access an individual market. * @return The list of market addresses */ function getEnteredMarkets( address addr ) public view returns (CToken[] memory) { return accountAssets[addr]; } /** * @notice Returns true if the given cToken market has been deprecated * @dev All borrows in a deprecated cToken market can be immediately liquidated * @param cToken The market to check if deprecated */ function isDeprecated(CToken cToken) public view returns (bool) { return markets[address(cToken)].collateralFactorMantissa == 0 && borrowGuardianPaused[address(cToken)] == true && cToken.reserveFactorMantissa() == 1e18; } function getBlockNumber() public view virtual returns (uint) { return block.timestamp; } /** * @notice Event emitted when tokens are minted */ /** * @notice Event emitted when tokens are redeemed */ event Redeem( address cToken, address redeemer, uint redeemAmount, uint redeemTokens ); function emitRedeem( address redeemer, uint redeemAmount, uint redeemTokens ) external { require(markets[msg.sender].isListed, "unlisted"); emit Redeem(msg.sender, redeemer, redeemAmount, redeemTokens); } event Borrow( address cToken, address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows, uint256 accountStaticBorrows ); function emitBorrow( address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows, uint256 accountStaticBorrows ) external { require(markets[msg.sender].isListed, "unlisted"); emit Borrow( msg.sender, borrower, borrowAmount, accountBorrows, totalBorrows, accountStaticBorrows ); } event Mint( address indexed cToken, address minter, uint mintAmount, uint mintTokens ); function emitMint( address minter, uint mintAmount, uint mintTokens ) external { require(markets[msg.sender].isListed, "unlisted"); emit Mint(msg.sender, minter, mintAmount, mintTokens); } event RepayBorrow( address indexed cToken, address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows, uint accountStaticBorrows ); function emitRepayBorrow( address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows, uint accountStaticBorrows ) external { require(markets[msg.sender].isListed, "unlisted"); emit RepayBorrow( msg.sender, payer, borrower, repayAmount, accountBorrows, totalBorrows, accountStaticBorrows ); } event LiquidateBorrow( address indexed cToken, address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens ); function emitLiquidateBorrow( address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens ) external { require(markets[msg.sender].isListed, "unlisted"); emit LiquidateBorrow( msg.sender, liquidator, borrower, repayAmount, cTokenCollateral, seizeTokens ); } event AccrueInterest( address indexed cToken, uint interestAccumulated, uint borrowIndex, uint exchangeRate ); function emitAccrueInterest(uint256 acc, uint256 bi, uint256 er) external { require(markets[msg.sender].isListed, "unlisted"); emit AccrueInterest(msg.sender, acc, bi, er); } event Transferred( address indexed cToken, address src, address dst, uint256 srcBalance, uint256 dstBalance ); function emitTransfer( address src, address dst, uint srcBalance, uint dstBalance ) external { require(markets[msg.sender].isListed, "unlisted"); emit Transferred(msg.sender, src, dst, srcBalance, dstBalance); } }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "./CToken.sol"; import "./PriceOracle.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; contract UnitrollerAdminStorage { /** * @notice Administrator for this contract */ address public admin; /** * @notice Pending administrator for this contract */ address public pendingAdmin; /** * @notice Active brains of Unitroller */ address public comptrollerImplementation; /** * @notice Pending brains of Unitroller */ address public pendingComptrollerImplementation; } contract ComptrollerV1Storage is UnitrollerAdminStorage { /** * @notice Oracle which gives the price of any given asset */ PriceOracle public oracle; /** * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow */ uint public closeFactorMantissa = 0.9e18; /** * @notice Multiplier representing the discount on collateral that a liquidator receives */ uint public liquidationIncentiveMantissa = 1.05e18; /** * @notice Max number of assets a single account can participate in (borrow or use as collateral) */ uint public maxAssets = type(uint256).max; /** * @notice Per-account mapping of "assets you are in", capped by maxAssets */ mapping(address => CToken[]) public accountAssets; } contract ComptrollerV2Storage is ComptrollerV1Storage { struct Market { // Whether or not this market is listed bool isListed; // Multiplier representing the most one can borrow against their collateral in this market. // For instance, 0.9 to allow borrowing 90% of collateral value. // Must be between 0 and 1, and stored as a mantissa. uint collateralFactorMantissa; // Per-market mapping of "accounts in this asset" mapping(address => bool) accountMembership; } /** * @notice Official mapping of cTokens -> Market metadata * @dev Used e.g. to determine if a market is supported */ mapping(address => Market) public markets; /** * @notice The Pause Guardian can pause certain actions as a safety mechanism. * Actions which allow users to remove their own assets cannot be paused. * Liquidation / seizing / transfer can only be paused globally, not by market. */ address public pauseGuardian; bool public _mintGuardianPaused; bool public _borrowGuardianPaused; bool public transferGuardianPaused; bool public seizeGuardianPaused; mapping(address => bool) public mintGuardianPaused; mapping(address => bool) public borrowGuardianPaused; } contract ComptrollerV3Storage is ComptrollerV2Storage { /// @notice A list of all markets CToken[] public allMarkets; } contract ComptrollerV4Storage is ComptrollerV3Storage { // @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market. address public borrowCapGuardian; // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. mapping(address => uint) public borrowCaps; } contract ComptrollerV5Storage is ComptrollerV4Storage {} contract ComptrollerV6Storage is ComptrollerV5Storage {} contract ComptrollerV7Storage is ComptrollerV6Storage { /// @notice Flag indicating whether the function to fix COMP accruals has been executed (RE: proposal 62 bug) address whitelistedLiquidator; }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; /** * @title ERC 20 Token Standard Interface * https://eips.ethereum.org/EIPS/eip-20 */ interface EIP20Interface { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); /** * @notice Get the total number of tokens in circulation * @return The supply of tokens */ function totalSupply() external view returns (uint256); /** * @notice Gets the balance of the specified address * @param owner The address from which the balance will be retrieved * @return balance The balance */ function balanceOf(address owner) external view returns (uint256 balance); /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return success Whether or not the transfer succeeded */ function transfer(address dst, uint256 amount) external returns (bool success); /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return success Whether or not the transfer succeeded */ function transferFrom(address src, address dst, uint256 amount) external returns (bool success); /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (-1 means infinite) * @return success Whether or not the approval succeeded */ function approve(address spender, uint256 amount) external returns (bool success); /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return remaining The number of tokens allowed to be spent (-1 means infinite) */ function allowance(address owner, address spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; /** * @title EIP20NonStandardInterface * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ interface EIP20NonStandardInterface { /** * @notice Get the total number of tokens in circulation * @return The supply of tokens */ function totalSupply() external view returns (uint256); /** * @notice Gets the balance of the specified address * @param owner The address from which the balance will be retrieved * @return balance The balance */ function balanceOf(address owner) external view returns (uint256 balance); /// /// !!!!!!!!!!!!!! /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification /// !!!!!!!!!!!!!! /// /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transfer(address dst, uint256 amount) external; /// /// !!!!!!!!!!!!!! /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification /// !!!!!!!!!!!!!! /// /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transferFrom(address src, address dst, uint256 amount) external; /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved * @return success Whether or not the approval succeeded */ function approve( address spender, uint256 amount ) external returns (bool success); /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return remaining The number of tokens allowed to be spent */ function allowance( address owner, address spender ) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval( address indexed owner, address indexed spender, uint256 amount ); }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; contract ComptrollerErrorReporter { enum Error { NO_ERROR, UNAUTHORIZED, COMPTROLLER_MISMATCH, INSUFFICIENT_SHORTFALL, INSUFFICIENT_LIQUIDITY, INVALID_CLOSE_FACTOR, INVALID_COLLATERAL_FACTOR, INVALID_LIQUIDATION_INCENTIVE, MARKET_NOT_ENTERED, // no longer possible MARKET_NOT_LISTED, MARKET_ALREADY_LISTED, MATH_ERROR, NONZERO_BORROW_BALANCE, PRICE_ERROR, REJECTION, SNAPSHOT_ERROR, TOO_MANY_ASSETS, TOO_MUCH_REPAY } enum FailureInfo { ACCEPT_ADMIN_PENDING_ADMIN_CHECK, ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, EXIT_MARKET_BALANCE_OWED, EXIT_MARKET_REJECTION, SET_CLOSE_FACTOR_OWNER_CHECK, SET_CLOSE_FACTOR_VALIDATION, SET_COLLATERAL_FACTOR_OWNER_CHECK, SET_COLLATERAL_FACTOR_NO_EXISTS, SET_COLLATERAL_FACTOR_VALIDATION, SET_COLLATERAL_FACTOR_WITHOUT_PRICE, SET_IMPLEMENTATION_OWNER_CHECK, SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, SET_LIQUIDATION_INCENTIVE_VALIDATION, SET_MAX_ASSETS_OWNER_CHECK, SET_PENDING_ADMIN_OWNER_CHECK, SET_PENDING_IMPLEMENTATION_OWNER_CHECK, SET_PRICE_ORACLE_OWNER_CHECK, SUPPORT_MARKET_EXISTS, SUPPORT_MARKET_OWNER_CHECK, SET_PAUSE_GUARDIAN_OWNER_CHECK } /** * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary * contract-specific code that enables us to report opaque error codes from upgradeable contracts. **/ event Failure(uint error, uint info, uint detail); /** * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator */ function fail(Error err, FailureInfo info) internal returns (uint) { emit Failure(uint(err), uint(info), 0); return uint(err); } /** * @dev use this when reporting an opaque error from an upgradeable collaborator contract */ function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { emit Failure(uint(err), uint(info), opaqueError); return uint(err); } } contract TokenErrorReporter { uint public constant NO_ERROR = 0; // support legacy return codes error TransferComptrollerRejection(uint256 errorCode); error TransferNotAllowed(); error TransferNotEnough(); error TransferTooMuch(); error MintComptrollerRejection(uint256 errorCode); error MintFreshnessCheck(); error RedeemComptrollerRejection(uint256 errorCode); error RedeemFreshnessCheck(); error RedeemTransferOutNotPossible(); error BorrowComptrollerRejection(uint256 errorCode); error BorrowFreshnessCheck(); error BorrowCashNotAvailable(); error RepayBorrowComptrollerRejection(uint256 errorCode); error RepayBorrowFreshnessCheck(); error LiquidateComptrollerRejection(uint256 errorCode); error LiquidateFreshnessCheck(); error LiquidateCollateralFreshnessCheck(); error LiquidateAccrueBorrowInterestFailed(uint256 errorCode); error LiquidateAccrueCollateralInterestFailed(uint256 errorCode); error LiquidateLiquidatorIsBorrower(); error LiquidateCloseAmountIsZero(); error LiquidateCloseAmountIsUintMax(); error LiquidateRepayBorrowFreshFailed(uint256 errorCode); error LiquidateSeizeComptrollerRejection(uint256 errorCode); error LiquidateSeizeLiquidatorIsBorrower(); error AcceptAdminPendingAdminCheck(); error SetComptrollerOwnerCheck(); error SetPendingAdminOwnerCheck(); error SetReserveFactorAdminCheck(); error SetReserveFactorFreshCheck(); error SetReserveFactorBoundsCheck(); error AddReservesFactorFreshCheck(uint256 actualAddAmount); error ReduceReservesAdminCheck(); error ReduceReservesFreshCheck(); error ReduceReservesCashNotAvailable(); error ReduceReservesCashValidation(); error SetInterestRateModelOwnerCheck(); error SetInterestRateModelFreshCheck(); }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; /** * @title Exponential module for storing fixed-precision decimals * @author Compound * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: * `Exp({mantissa: 5100000000000000000})`. */ contract ExponentialNoError { uint constant expScale = 1e18; uint constant doubleScale = 1e36; uint constant halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { uint mantissa; } struct Double { uint mantissa; } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) pure internal returns (uint) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { Exp memory product = mul_(a, scalar); return truncate(product); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { Exp memory product = mul_(a, scalar); return add_(truncate(product), addend); } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) pure internal returns (bool) { return value.mantissa == 0; } function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { require(n < 2**224, errorMessage); return uint224(n); } function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(uint a, uint b) pure internal returns (uint) { return a + b; } function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(uint a, uint b) pure internal returns (uint) { return a - b; } function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); } function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Exp memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / expScale; } function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); } function mul_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Double memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / doubleScale; } function mul_(uint a, uint b) pure internal returns (uint) { return a * b; } function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); } function div_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Exp memory b) pure internal returns (uint) { return div_(mul_(a, expScale), b.mantissa); } function div_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); } function div_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Double memory b) pure internal returns (uint) { return div_(mul_(a, doubleScale), b.mantissa); } function div_(uint a, uint b) pure internal returns (uint) { return a / b; } function fraction(uint a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a, doubleScale), b)}); } }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; /** * @title Compound's InterestRateModel Interface * @author Compound */ abstract contract InterestRateModel { /// @notice Indicator that this is an InterestRateModel contract (for inspection) bool public constant isInterestRateModel = true; /** * @notice Calculates the current borrow interest rate per block * @param cash The total amount of cash the market has * @param borrows The total amount of borrows the market has outstanding * @param reserves The total amount of reserves the market has * @return The borrow rate per block (as a percentage, and scaled by 1e18) */ function getBorrowRate(uint cash, uint borrows, uint reserves) virtual external view returns (uint); /** * @notice Calculates the current supply interest rate per block * @param cash The total amount of cash the market has * @param borrows The total amount of borrows the market has outstanding * @param reserves The total amount of reserves the market has * @param reserveFactorMantissa The current reserve factor the market has * @return The supply rate per block (as a percentage, and scaled by 1e18) */ function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) virtual external view returns (uint); }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "./CToken.sol"; abstract contract PriceOracle { /// @notice Indicator that this is a PriceOracle contract (for inspection) bool public constant isPriceOracle = true; /** * @notice Get the underlying price of a cToken asset * @param cToken The cToken to get the underlying price of * @return The underlying asset price mantissa (scaled by 1e18). * Zero means the price is unavailable. */ function getUnderlyingPrice( CToken cToken ) external view virtual returns (uint); }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.10; import "./ErrorReporter.sol"; import "./ComptrollerStorage.sol"; /** * @title ComptrollerCore * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`. * CTokens should reference this contract as their comptroller. */ contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { /** * @notice Emitted when pendingComptrollerImplementation is changed */ event NewPendingImplementation( address oldPendingImplementation, address newPendingImplementation ); /** * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated */ event NewImplementation( address oldImplementation, address newImplementation ); /** * @notice Emitted when pendingAdmin is changed */ event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); /** * @notice Emitted when pendingAdmin is accepted, which means admin is updated */ event NewAdmin(address oldAdmin, address newAdmin); constructor() { // Set admin to caller admin = msg.sender; } /*** Admin Functions ***/ function _setPendingImplementation( address newPendingImplementation ) public returns (uint) { if (msg.sender != admin) { return fail( Error.UNAUTHORIZED, FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK ); } address oldPendingImplementation = pendingComptrollerImplementation; pendingComptrollerImplementation = newPendingImplementation; emit NewPendingImplementation( oldPendingImplementation, pendingComptrollerImplementation ); return uint(Error.NO_ERROR); } /** * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation * @dev Admin function for new implementation to accept it's role as implementation * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _acceptImplementation() public returns (uint) { // Check caller is pendingImplementation and pendingImplementation ≠ address(0) if ( msg.sender != pendingComptrollerImplementation || pendingComptrollerImplementation == address(0) ) { return fail( Error.UNAUTHORIZED, FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK ); } // Save current values for inclusion in log address oldImplementation = comptrollerImplementation; address oldPendingImplementation = pendingComptrollerImplementation; comptrollerImplementation = pendingComptrollerImplementation; pendingComptrollerImplementation = address(0); emit NewImplementation(oldImplementation, comptrollerImplementation); emit NewPendingImplementation( oldPendingImplementation, pendingComptrollerImplementation ); return uint(Error.NO_ERROR); } /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setPendingAdmin(address newPendingAdmin) public returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail( Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK ); } // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); return uint(Error.NO_ERROR); } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _acceptAdmin() public returns (uint) { // Check caller is pendingAdmin and pendingAdmin ≠ address(0) if (msg.sender != pendingAdmin || msg.sender == address(0)) { return fail( Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK ); } // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = address(0); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); return uint(Error.NO_ERROR); } /** * @dev Delegates execution to an implementation contract. * It returns to the external caller whatever the implementation returns * or forwards reverts. */ fallback() external payable { // delegate all other functions to current implementation (bool success, ) = comptrollerImplementation.delegatecall(msg.data); assembly { let free_mem_ptr := mload(0x40) returndatacopy(free_mem_ptr, 0, returndatasize()) switch success case 0 { revert(free_mem_ptr, returndatasize()) } default { return(free_mem_ptr, returndatasize()) } } } }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.10; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../lib/RPow.sol"; import "../lib/Ledger.sol"; interface IRewardDistributor { function reap() external; function emissionRates() external returns (uint256, uint256); } struct ES33Parameters { uint256 initialSupply; uint256 maxSupply; uint256 decay; uint256 unstakingTime; uint256 protocolFeeRate; uint256 tradeStart; uint256 emissionStart; address[] rewardTokens; } contract ES33 is ERC20Upgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable { using LedgerLib for Ledger; using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; function slot(address a) internal pure returns (bytes32) { return bytes32(uint256(uint160(a))); } address distributor; uint256 public maxSupply; uint256 decay; // 1 - (emission per second / (maxSupply - totalSupply)), multiplied by (2 ** 128). uint256 unstakingTime; uint256 protocolFeeRate; uint256 tradeStart; uint256 lastMint; Ledger staked; Ledger unstaking; EnumerableSet.AddressSet rewardTokens; mapping(address => uint256) public unstakingEndDate; mapping(IERC20 => uint256) public accruedProtocolFee; event Stake(address from, uint256 amount); event StartUnstake(address from, uint256 amount); event CancelUnstake(address from, uint256 amount); event ClaimUnstake(address from, uint256 amount); event Donate(address from, address token, uint256 amount); event Harvest(address from, uint256 amount); function initialize( string memory name, string memory symbol, address admin, ES33Parameters calldata params ) external initializer { require(params.maxSupply > params.initialSupply); require(params.decay < 2 ** 128); maxSupply = params.maxSupply; decay = params.decay; unstakingTime = params.unstakingTime; protocolFeeRate = params.protocolFeeRate; _transferOwnership(admin); __ReentrancyGuard_init(); __ERC20_init(name, symbol); rewardTokens.add(address(this)); for (uint256 i = 0; i < params.rewardTokens.length; i++) { rewardTokens.add(params.rewardTokens[i]); } lastMint = Math.max(params.emissionStart, block.timestamp); tradeStart = params.tradeStart; _mint(admin, params.initialSupply); } function addRewardToken(address token) external onlyOwner { rewardTokens.add(token); } function setDistributor(address distributor_) external onlyOwner { distributor = distributor_; } function _mintEmission() internal returns (uint256) { if (block.timestamp <= lastMint) { return 0; } uint256 decayed = 2 ** 128 - RPow.rpow(decay, block.timestamp - lastMint, 2 ** 128); uint256 mintable = maxSupply - totalSupply(); uint256 emission = Math.mulDiv(mintable, decayed, 2 ** 128); lastMint = block.timestamp; _mint(distributor, emission); return emission; } function mintEmission() external returns (uint256) { require(msg.sender == address(distributor)); return _mintEmission(); } function circulatingSupply() public view returns (uint256) { return ERC20Upgradeable.totalSupply(); } function totalSupply() public view override returns (uint256) { return circulatingSupply() + unstaking.total + staked.total; } function stakeFor(address to, uint256 amount) external nonReentrant { _harvest(to, true); staked.deposit(slot(to), amount); _burn(msg.sender, amount); emit Stake(to, amount); } function stake(uint256 amount) external nonReentrant { _harvest(msg.sender, true); staked.deposit(slot(msg.sender), amount); _burn(msg.sender, amount); emit Stake(msg.sender, amount); } function startUnstaking() external nonReentrant { _harvest(msg.sender, true); uint256 amount = staked.withdrawAll(slot(msg.sender)); unstaking.deposit(slot(msg.sender), amount); unstakingEndDate[msg.sender] = block.timestamp + unstakingTime; emit StartUnstake(msg.sender, amount); } function cancelUnstaking() external nonReentrant { _harvest(msg.sender, true); uint256 amount = unstaking.withdrawAll(slot(msg.sender)); staked.deposit(slot(msg.sender), amount); emit CancelUnstake(msg.sender, amount); } function claimUnstaked() external nonReentrant { require(unstakingEndDate[msg.sender] <= block.timestamp); uint256 unstaked = unstaking.withdrawAll(slot(msg.sender)); emit ClaimUnstake(msg.sender, unstaked); _mint(msg.sender, unstaked); } function claimProtocolFee( IERC20 tok, address to ) external onlyOwner nonReentrant { uint256 amount = accruedProtocolFee[tok]; accruedProtocolFee[tok] = 0; tok.safeTransfer(to, amount); } function _harvest( address addr, bool reap ) internal returns (uint256[] memory) { if (reap) { IRewardDistributor(distributor).reap(); } address[] memory tokens = rewardTokens.values(); uint256[] memory amounts = new uint256[](tokens.length); for (uint256 i = 0; i < tokens.length; i++) { uint256 delta = IERC20(tokens[i]).balanceOf(address(this)) - staked.rewardsLeft(slot(tokens[i])); uint256 protocolFee = (delta * protocolFeeRate) / 1e18; accruedProtocolFee[IERC20(tokens[i])] += protocolFee; staked.reward(slot(tokens[i]), delta - protocolFee); if (addr == address(0)) { continue; } uint256 harvested = staked.harvest(slot(addr), slot(tokens[i])); amounts[i] = harvested; if (harvested > 0) { emit Harvest(addr, harvested); IERC20(tokens[i]).safeTransfer(addr, harvested); } } return amounts; } function harvest( bool reap ) external nonReentrant returns (uint256[] memory) { return _harvest(msg.sender, reap); } function _beforeTokenTransfer( address from, address to, uint256 ) internal view override { require( block.timestamp >= tradeStart || from == owner() || to == owner(), "trading not started yet." ); } //--- view functions function stakedBalanceOf(address acc) external view returns (uint256) { return staked.balances[slot(acc)]; } function unstakingBalanceOf(address acc) external view returns (uint256) { return unstaking.balances[slot(acc)]; } function emissionRate() external view returns (uint256) { uint256 decayed = 2 ** 128 - RPow.rpow(decay, block.timestamp - lastMint, 2 ** 128); uint256 mintable = maxSupply - totalSupply(); uint256 emission = Math.mulDiv(mintable, decayed, 2 ** 128); return Math.mulDiv(mintable - emission, 2 ** 128 - decay, 2 ** 128); } function rewardRate() external returns (uint256, uint256) { _harvest(address(0), true); (uint256 selfRate, uint256 vcRate) = IRewardDistributor(distributor) .emissionRates(); return ( (selfRate * (1e18 - protocolFeeRate)) / staked.total, (vcRate * (1e18 - protocolFeeRate)) / staked.total ); } }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.10; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../lib/Ledger.sol"; import "../CToken.sol"; import "../CErc20.sol"; import "../interfaces/IRouter.sol"; import "../interfaces/IPair.sol"; import "../interfaces/IWETH.sol"; import "./ES33.sol"; interface IBribe { function notifyRewardAmount(address token, uint256 amount) external; } interface IGauge { function getReward(address account, address[] memory tokens) external; function rewardRate(address) external returns (uint256); function deposit(uint256 amount, uint256 tokenId) external; function stake() external returns (address); function balanceOf(address) external returns (uint256); function totalSupply() external returns (uint256); } interface IComptroller { function getAllMarkets() external view returns (address[] memory); } contract RewardDistributor is OwnableUpgradeable, ReentrancyGuardUpgradeable { using LedgerLib for Ledger; using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; bytes32 public constant BRIBE_ACCOUNT = bytes32("BRIBE"); ES33 public underlying; address cEther; address weth; IBribe bribe; IGauge gauge; IERC20 vc; IRouter router; IComptroller comptroller; Ledger weights; mapping(bytes32 => Ledger) assetLedgers; mapping(address => uint256) accruedInterest; uint256 supposedBalance; // unused. included for historical reasons uint256 public lastReap; uint256 public lastGaugeClaim; uint256 public duration; uint256 public swappedRF; event Harvest(address addr, uint256 amount); function initialize( address admin, ES33 underlying_, address cEther_, address weth_, IRouter router_ ) external initializer { _transferOwnership(admin); __ReentrancyGuard_init(); underlying = underlying_; cEther = cEther_; weth = weth_; router = router_; } function stakeLP() external onlyOwner { address stakeToken = gauge.stake(); uint256 balance = IERC20(stakeToken).balanceOf(address(this)); IERC20(stakeToken).approve(address(gauge), balance); gauge.deposit(balance, 0); } // todo: takeLP function slot(address a) internal pure returns (bytes32) { return bytes32(uint256(uint160(a))); } function slot(IERC20 a) internal pure returns (bytes32) { return slot(address(a)); } function slot( address informationSource, bytes32 kind ) public pure returns (bytes32) { return keccak256(abi.encode(informationSource, kind)); } function setExternals( IBribe bribe_, IGauge gauge_, IERC20 vc_, IComptroller comptroller_ ) external onlyOwner { bribe = bribe_; gauge = gauge_; vc = vc_; comptroller = comptroller_; } function onAssetIncrease( bytes32 kind, address account, uint256 delta ) external nonReentrant { bytes32[] memory a = new bytes32[](1); a[0] = slot(msg.sender, kind); _harvest(account, a); Ledger storage ledger = assetLedgers[slot(msg.sender, kind)]; ledger.deposit(slot(account), delta); } function onAssetDecrease( bytes32 kind, address account, uint256 delta ) external nonReentrant { bytes32[] memory a = new bytes32[](1); a[0] = slot(msg.sender, kind); _harvest(account, a); Ledger storage ledger = assetLedgers[slot(msg.sender, kind)]; ledger.withdraw(slot(account), delta); } function onAssetChange( bytes32 kind, address account, uint256 amount ) external nonReentrant { bytes32[] memory a = new bytes32[](1); a[0] = slot(msg.sender, kind); _harvest(account, a); Ledger storage ledger = assetLedgers[slot(msg.sender, kind)]; ledger.withdrawAll(slot(account)); ledger.deposit(slot(account), amount); } function _harvest( address addr, bytes32[] memory ledgerIds ) internal returns (uint256) { updateRewards(ledgerIds); uint256 harvested = 0; for (uint256 j = 0; j < ledgerIds.length; j++) { harvested += assetLedgers[ledgerIds[j]].harvest( slot(addr), slot(address(underlying)) ); } accruedInterest[addr] += harvested; return harvested; } function harvest( bytes32[] memory ledgerIds ) external nonReentrant returns (uint256) { _harvest(msg.sender, ledgerIds); uint256 amount = accruedInterest[msg.sender]; accruedInterest[msg.sender] = 0; IERC20(address(underlying)).safeTransfer(msg.sender, amount); emit Harvest(msg.sender, amount); return amount; } function updateRewards(bytes32[] memory ledgerIds) public { uint256 delta = underlying.mintEmission(); if (delta != 0) { weights.reward(slot(address(underlying)), delta); } for (uint256 j = 0; j < ledgerIds.length; j++) { if (ledgerIds[j] != BRIBE_ACCOUNT) { uint256 amount = weights.harvest( ledgerIds[j], slot(address(underlying)) ); assetLedgers[ledgerIds[j]].reward( slot(address(underlying)), amount ); } } uint256 bribeAmount = weights.harvest( BRIBE_ACCOUNT, slot(address(underlying)) ); if (bribeAmount > 0) { underlying.approve(address(bribe), bribeAmount); bribe.notifyRewardAmount(address(underlying), bribeAmount); } } function setWeights( bytes32[] calldata _ids, uint256[] calldata _weights ) external onlyOwner nonReentrant { updateRewards(_ids); for (uint256 i = 0; i < _ids.length; i++) { weights.withdrawAll(_ids[i]); weights.deposit(_ids[i], _weights[i]); } } function borrowSlot(address cToken) external pure returns (bytes32) { return slot(cToken, bytes32("BORROW")); } function supplySlot(address cToken) external pure returns (bytes32) { return slot(cToken, bytes32("SUPPLY")); } function reset() external onlyOwner { lastGaugeClaim = block.timestamp - 10 minutes - 1; duration = 10 minutes; } function reap() public nonReentrant returns (uint256, uint256) { if (lastReap == block.timestamp) return (0, 0); // hardcoded to save gas IERC20 usdc = IERC20(0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4); CToken ceth = CToken(0xC5db68F30D21cBe0C9Eac7BE5eA83468d69297e6); CToken cusdc = CToken(0x04e9Db37d8EA0760072e1aCE3F2A219988Fdac29); IPair ethrf = IPair(0x62eB02CB53673b5855f2C0Ea4B8fE198901F34Ac); IPair usdceth = IPair(0xcD52cbc975fbB802F82A1F92112b1250b5a997Df); uint256 vc_delta; uint256 vcBal = vc.balanceOf(address(this)); uint256 rf_delta; if (block.timestamp - lastGaugeClaim >= duration) { rf_delta += swappedRF; swappedRF = 0; ceth.takeReserves(); cusdc.takeReserves(); uint256 wethTotal = 0; uint256 usdcbal = usdc.balanceOf(address(this)); uint256 usdcWethOut = usdceth.getAmountOut(usdcbal, address(usdc)); if (usdcWethOut > 0) { usdc.transfer(address(usdceth), usdcbal); usdceth.swap(0, usdcWethOut, address(ethrf), ""); wethTotal += usdcWethOut; } uint256 ethbal = address(this).balance; IWETH(weth).deposit{value: ethbal}(); IWETH(weth).transfer(address(ethrf), ethbal); wethTotal += ethbal; uint256 rfOut = ethrf.getAmountOut(wethTotal, address(weth)); if (rfOut > 0) { ethrf.swap(0, rfOut, address(this), ""); } swappedRF = rfOut; address[] memory b = new address[](1); b[0] = address(vc); vc_delta += vcBal; gauge.getReward(address(this), b); vcBal = vc.balanceOf(address(this)) - vcBal; lastReap = lastGaugeClaim + duration; lastGaugeClaim = block.timestamp; duration = Math.min(1 days, (duration * 15) / 10); } if (lastGaugeClaim + duration > lastReap) { vc_delta += (vcBal * (block.timestamp - lastReap)) / (lastGaugeClaim + duration - lastReap); uint256 rf_delta_new = (swappedRF * (block.timestamp - lastReap)) / (lastGaugeClaim + duration - lastReap); rf_delta += rf_delta_new; if (rf_delta_new <= swappedRF) { swappedRF -= rf_delta_new; } else { swappedRF = 0; } } lastReap = block.timestamp; if (vc_delta > 0) vc.transfer(address(underlying), vc_delta); if (rf_delta > 0) underlying.transfer(address(underlying), rf_delta); return (rf_delta, vc_delta); } receive() external payable {} //--- view functions function currentPrice( IERC20 qtyToken, IERC20 quoteToken ) internal view returns (uint256) { IPair pair = IPair( router.pairFor(address(qtyToken), address(quoteToken), false) ); (uint256 r0, uint256 r1, ) = pair.getReserves(); (IERC20 t0, ) = pair.tokens(); return qtyToken == t0 ? Math.mulDiv(1e18, r1, r0) : Math.mulDiv(1e18, r0, r1); } function rewardRateAll() external returns ( address[] memory cts, uint256[] memory supplies, uint256[] memory borrows ) { cts = comptroller.getAllMarkets(); supplies = new uint256[](cts.length); borrows = new uint256[](cts.length); uint256 totalRate = underlying.emissionRate(); for (uint256 i = 0; i < cts.length; i++) { supplies[i] = CToken(cts[i]).totalSupply() == 0 ? 0 : ((totalRate * weights.shareOf(slot(cts[i], bytes32("SUPPLY")))) * 1e18) / (CToken(cts[i]).totalSupply() * CToken(cts[i]).exchangeRateCurrent()); borrows[i] = (CToken(cts[i]).totalBorrowsCurrent()) == 0 ? 0 : ( (totalRate * weights.shareOf(slot(cts[i], bytes32("BORROW")))) ) / (CToken(cts[i]).totalBorrowsCurrent()); } return (cts, supplies, borrows); } function emissionRates() external returns (uint256, uint256) { reap(); address[] memory cts = comptroller.getAllMarkets(); uint256 totalES33Rate = 0; uint256 ethPrice = currentPrice( IERC20(weth), IERC20(address(underlying)) ); for (uint256 i = 0; i < cts.length; i++) { CErc20 ct = CErc20(cts[i]); uint256 totalInterests = Math.mulDiv( ct.totalBorrowsCurrent(), ct.borrowRatePerBlock(), 1e18 ); uint256 tokenInflow = Math.mulDiv( totalInterests, ct.reserveFactorMantissa(), 1e18 ); uint256 ethConversionRate = address(ct) == cEther ? 1e18 : currentPrice(IERC20(ct.underlying()), IERC20(weth)); uint256 ethInflow = Math.mulDiv( tokenInflow, ethConversionRate, 1e18 ); totalES33Rate += Math.mulDiv(ethInflow, ethPrice, 1e18); } uint256 totalVCRate = (gauge.rewardRate(address(vc)) * gauge.balanceOf(address(this))) / gauge.totalSupply(); return (totalES33Rate, totalVCRate); } }
pragma solidity ^0.8.13; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IPair { function metadata() external view returns ( uint dec0, uint dec1, uint r0, uint r1, bool st, address t0, address t1 ); function setExternalBribe(address _externalBribe) external; function setHasGauge(bool value) external; function tokens() external view returns (IERC20, IERC20); function transferFrom( address src, address dst, uint amount ) external returns (bool); function permit( address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s ) external; function swap( uint amount0Out, uint amount1Out, address to, bytes calldata data ) external; function burn(address to) external returns (uint amount0, uint amount1); function mint(address to) external returns (uint liquidity); function getReserves() external view returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast); function getAmountOut(uint, address) external view returns (uint); }
pragma solidity ^0.8.13; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; struct route { address from; address to; bool stable; } interface IRouter { function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, route[] calldata routes, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactETHForTokens( uint256 amountOutMin, route[] calldata routes, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function addLiquidityETH( address token, bool stable, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable; function pairFor( address tokenA, address tokenB, bool stable ) external view returns (address pair); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @dev Interface for WETH9. * See https://github.com/gnosis/canonical-weth/blob/0dd1ea3e295eef916d0c6223ec63141137d22d67/contracts/WETH9.sol */ interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.10; import "@openzeppelin/contracts/utils/math/Math.sol"; struct Ledger { uint256 total; mapping(bytes32 => uint256) balances; mapping(bytes32 => Emission) emissions; } struct Emission { uint256 current; uint256 balance; mapping(bytes32 => uint256) snapshots; } library LedgerLib { using LedgerLib for Ledger; function deposit( Ledger storage self, bytes32 account, uint256 amount ) internal { self.total += amount; self.balances[account] += amount; } function shareOf( Ledger storage self, bytes32 account ) internal view returns (uint256) { if (self.total == 0) return 0; return (self.balances[account] * 1e18) / self.total; } function withdraw( Ledger storage self, bytes32 account, uint256 amount ) internal { self.total -= amount; self.balances[account] -= amount; } function withdrawAll( Ledger storage self, bytes32 account ) internal returns (uint256) { uint256 amount = self.balances[account]; self.withdraw(account, amount); return amount; } function reward( Ledger storage self, bytes32 emissionToken, uint256 amount ) internal { Emission storage emission = self.emissions[emissionToken]; if (self.total != 0) { emission.current += (amount * 1e18) / self.total; } emission.balance += amount; } function harvest( Ledger storage self, bytes32 account, bytes32 emissionToken ) internal returns (uint256) { Emission storage emission = self.emissions[emissionToken]; uint256 harvested = (self.balances[account] * (emission.current - emission.snapshots[account])) / 1e18; emission.snapshots[account] = emission.current; emission.balance -= harvested; return harvested; } function rewardsLeft( Ledger storage self, bytes32 emissionToken ) internal view returns (uint256) { Emission storage emission = self.emissions[emissionToken]; return emission.balance; } }
// SPDX-License-Identifier: AGPL-3.0-or-later // From MakerDAO DSS // Copyright (C) 2018 Rain <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity ^0.8.0; library RPow { function rpow(uint x, uint n, uint base) internal pure returns (uint z) { assembly { switch x case 0 { switch n case 0 { z := base } default { z := 0 } } default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0, 0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, base) if mod(n, 2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, base) } } } } } }
{ "compilerPath": "./zksolc", "experimental": {}, "forceEvmla": false, "isSystem": false, "libraries": {}, "optimizer": { "enabled": true, "mode": "3" } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract Comptroller","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"},{"internalType":"bytes32","name":"pythId","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AcceptAdminPendingAdminCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualAddAmount","type":"uint256"}],"name":"AddReservesFactorFreshCheck","type":"error"},{"inputs":[],"name":"BorrowCashNotAvailable","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"BorrowComptrollerRejection","type":"error"},{"inputs":[],"name":"BorrowFreshnessCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateAccrueBorrowInterestFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateAccrueCollateralInterestFailed","type":"error"},{"inputs":[],"name":"LiquidateCloseAmountIsUintMax","type":"error"},{"inputs":[],"name":"LiquidateCloseAmountIsZero","type":"error"},{"inputs":[],"name":"LiquidateCollateralFreshnessCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateComptrollerRejection","type":"error"},{"inputs":[],"name":"LiquidateFreshnessCheck","type":"error"},{"inputs":[],"name":"LiquidateLiquidatorIsBorrower","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateRepayBorrowFreshFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateSeizeComptrollerRejection","type":"error"},{"inputs":[],"name":"LiquidateSeizeLiquidatorIsBorrower","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"MintComptrollerRejection","type":"error"},{"inputs":[],"name":"MintFreshnessCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"RedeemComptrollerRejection","type":"error"},{"inputs":[],"name":"RedeemFreshnessCheck","type":"error"},{"inputs":[],"name":"RedeemTransferOutNotPossible","type":"error"},{"inputs":[],"name":"ReduceReservesAdminCheck","type":"error"},{"inputs":[],"name":"ReduceReservesCashNotAvailable","type":"error"},{"inputs":[],"name":"ReduceReservesCashValidation","type":"error"},{"inputs":[],"name":"ReduceReservesFreshCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"RepayBorrowComptrollerRejection","type":"error"},{"inputs":[],"name":"RepayBorrowFreshnessCheck","type":"error"},{"inputs":[],"name":"SetComptrollerOwnerCheck","type":"error"},{"inputs":[],"name":"SetInterestRateModelFreshCheck","type":"error"},{"inputs":[],"name":"SetInterestRateModelOwnerCheck","type":"error"},{"inputs":[],"name":"SetPendingAdminOwnerCheck","type":"error"},{"inputs":[],"name":"SetReserveFactorAdminCheck","type":"error"},{"inputs":[],"name":"SetReserveFactorBoundsCheck","type":"error"},{"inputs":[],"name":"SetReserveFactorFreshCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"TransferComptrollerRejection","type":"error"},{"inputs":[],"name":"TransferNotAllowed","type":"error"},{"inputs":[],"name":"TransferNotEnough","type":"error"},{"inputs":[],"name":"TransferTooMuch","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":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract Comptroller","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract Comptroller","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","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"},{"inputs":[],"name":"NO_ERROR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_addReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Comptroller","name":"newComptroller","type":"address"}],"name":"_setComptroller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","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":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract Comptroller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dist","outputs":[{"internalType":"contract RewardDistributor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"getSnapshots","outputs":[{"internalType":"uint256[2][]","name":"","type":"uint256[2][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"acc","type":"address"}],"name":"getStaticBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Comptroller","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"bytes32","name":"pythFeedID_","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"contract CToken","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolSeizeShareMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pythFeedID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"repayBorrowBehalf","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"takeReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"dist_","type":"address"}],"name":"updateDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
9c4d535b0000000000000000000000000000000000000000000000000000000000000000010008631f496f6dc6a67a67e2303b6fdde4c498ca5dfad563033b1b09b24f390000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000023848c28af1c3aa7b999fa57e6b6e8599c17f3f2000000000000000000000000727d77d4ef5e5c75f4e0c4716d7a7a55c1467e5c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000001200000000000000000000000099999a3c4cb8427c44294ad36895b6a3a047060dff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace000000000000000000000000000000000000000000000000000000000000001352656163746f72467573696f6e2045746865720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057266455448000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x0004000000000002000e00000000000200000000030100190000006003300270000007b10430019700030000004103550002000000010355000007b10030019d000100000000001f00000001012001900000000c0000c13d1ebd03130000040f0000008001000039000000400010043f0000000001000416000000000110004c000001940000c13d00000000010000310000009f02100039000000200800008a000000000282016f000007b203200041000007b30330009c0000001f0000213d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000400020043f0000001f0210018f000000020300036700000005041002720000002d0000613d00000000050000190000000506500210000000000763034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000250000413d000000000520004c0000003c0000613d0000000504400210000000000343034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f0000000000240435000007b402000041000001000310008c00000000030000190000000003024019000007b404100197000000000540004c000000000200a019000007b40440009c000000000203c019000000000220004c000001940000c13d000000800200043d000007b505200197000007b50220009c000001940000213d000000a00200043d000007b504200197000007b50220009c000001940000213d000000c00200043d000e00000002001d000000e00600043d000007b60360009c000001940000213d00000080021000390000008001600039000c00000002001d000900000008001d000b00000004001d000d00000005001d1ebd10ae0000040f000a00000001001d000001000100043d000007b60210009c000001940000213d00000080011000390000000c020000291ebd10ae0000040f0000000d080000290000000007010019000001200400043d000000ff0140008c000001940000213d000001400500043d000007b50150009c000001940000213d0000000306000039000000000106041a000007b70110019700000000020004110000000803200210000007b803300197000000000113019f000001600300043d000000000016041b000007b90120009c0000009a0000813d0000000902000039000000000102041a000000000110004c000000ab0000c13d0000000a09000039000000000109041a000000000110004c000000ab0000c13d000800000009001d000c00000002001d000700000007001d000300000003001d000400000006001d000500000005001d000600000004001d00000007010000390000000e02000029000000000021041b000000000120004c000000bc0000c13d000000400100043d0000006402100039000007ca0300004100000000003204350000004402100039000007cb030000410000000000320435000000240210003900000030030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000084020000391ebd030a0000040f000000400100043d0000006402100039000007ba0300004100000000003204350000004402100039000007bb030000410000000000320435000000240210003900000024030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000084020000391ebd030a0000040f000000400100043d0000006402100039000007bd0300004100000000003204350000004402100039000007be030000410000000000320435000000240210003900000023030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000084020000391ebd030a0000040f0000000501000039000100000001001d000000000101041a000200000001001d000000400200043d000007bf01000041000e00000002001d00000000001204350000000001000414000000040280008c000000ef0000613d000000040400003900000020060000390000000d020000290000000e0300002900000000050300191ebd02a00000040f000000000110004c000000ef0000c13d0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000000de0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000000d60000413d000000000530004c000000ed0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f0000000e0200002900000000050200190000000002230019000000000332004b00000000030000190000000103004039000007b60420009c000000180000213d0000000103300190000000180000c13d000000400020043f000000200110008c0000000d03000029000001940000413d0000000001050433000000000210004c0000000002000019000000010200c039000000000221004b000001940000c13d1ebd10ea0000040f0000000203000029000007c0013001970000000d04000029000000000141019f0000000102000029000000000012041b000000400100043d00000020021000390000000000420435000007b5023001970000000000210435000007b1020000410000000003000414000007b10430009c0000000003028019000007b10410009c00000000010280190000004001100210000000c002300210000000000112019f000007c1011001c70000800d020000390000000103000039000007c2040000411ebd1eb30000040f0000000b030000290000000101200190000001940000613d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000c02000029000000000012041b000007c4010000410000000802000029000000000012041b0000000601000039000c00000001001d000000000101041a000d00000001001d000007c501000041000000400200043d000e00000002001d000000000012043500000000010004140000000b02000029000000040220008c000001440000613d000000040400003900000020060000390000000b020000290000000e0300002900000000050300191ebd02a00000040f000000000110004c000000cf0000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f0000000e020000290000000002230019000000000332004b00000000030000190000000103004039000007b60420009c000000180000213d0000000103300190000000180000c13d000000400020043f000000200110008c0000000b03000029000001940000413d0000000e010000290000000001010433000000000210004c0000000002000019000000010200c039000000000221004b000001940000c13d1ebd10ea0000040f0000000d03000029000007c0013001970000000b04000029000000000141019f0000000c02000029000000000012041b000000400100043d00000020021000390000000000420435000007b5023001970000000000210435000007b1020000410000000003000414000007b10430009c0000000003028019000007b10410009c00000000010280190000004001100210000000c002300210000000000112019f000007c1011001c70000800d020000390000000103000039000007c604000041000e00000003001d1ebd1eb30000040f0000000101200190000001940000613d0000000a010000290000000001010433000d00000001001d000007b60110009c000000180000213d0000000e01000029000000000101041a000000010210019000000001011002700000007f0310018f0000000001036019000c00000001001d0000001f0110008c00000000010000190000000101002039000000010110018f000000000112004b000001970000613d000007c90100004100000000001004350000002201000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000000100001900000000020000191ebd030a0000040f0000000c01000029000000200110008c000001af0000413d00000001010000390000000000100435000000200200003900000000010000191ebd02d70000040f0000000d030000290000001f023000390000000502200270000000200330008c000000000302001900000000030040190000000c020000290000001f02200039000000050220027000000000022100190000000001310019000000000321004b000001af0000813d000000000001041b0000000101100039000001aa0000013d0000000d010000290000001f0110008c000001c80000a13d0000000101000039000c00000001001d00000000001004350000002002000039000b00000002001d00000000010000191ebd02d70000040f0000000b0600002900000009020000290000000d03000029000000000223016f00000000030000190000000a05000029000000000423004b0000000004560019000001d80000813d0000000004040433000000000041041b000000200330003900000020066000390000000101100039000001bf0000013d0000000d01000029000000000110004c0000000001000019000001cf0000613d0000000a01000029000000200110003900000000010104330000000d040000290000000302400210000000010300008a000000000223022f000000000232013f000000000121016f0000000102400210000c00000002001d000001e60000013d0000000d03000029000000000232004b000001e40000813d0000000d020000290000000302200210000000f80220018f000000010300008a000000000223022f000000000232013f0000000003040433000000000223016f000000000021041b0000000d0100002900000001011002100000000c02000029000000000121019f0000000e02000029000000000012041b00000007010000290000000001010433000d00000001001d000007b60110009c000000180000213d0000000201000039000c00000001001d000000000101041a000000010210019000000001021002700000007f0320018f0000000002036019000b00000002001d0000001f0220008c00000000020000190000000102002039000000000121013f00000001011001900000018d0000c13d0000000b01000029000000200110008c000002150000413d0000000c010000290000000000100435000000200200003900000000010000191ebd02d70000040f0000000d030000290000001f023000390000000502200270000000200330008c000000000302001900000000030040190000000b020000290000001f02200039000000050220027000000000022100190000000001310019000000000321004b000002150000813d000000000001041b0000000101100039000002100000013d0000000d010000290000001f0110008c0000022d0000a13d0000000c0100002900000000001004350000002002000039000b00000002001d00000000010000191ebd02d70000040f0000000b0600002900000009020000290000000d03000029000000000223016f00000000030000190000000705000029000000000423004b00000000045600190000023d0000813d0000000004040433000000000041041b000000200330003900000020066000390000000101100039000002240000013d0000000d01000029000000000110004c0000000001000019000002340000613d0000000701000029000000200110003900000000010104330000000d040000290000000302400210000000010300008a000000000223022f000000000232013f000000000121016f0000000102400210000e00000002001d0000024b0000013d0000000d03000029000000000232004b000002490000813d0000000d020000290000000302200210000000f80220018f000000010300008a000000000223022f000000000232013f0000000003040433000000000223016f000000000021041b0000000d0100002900000001011002100000000e02000029000000000121019f0000000c02000029000000000012041b0000000404000029000000000104041a00000011020000390000000303000029000000000032041b000001000200008a000000000300041a000000000223016f00000001022001bf000000000020041b0000000602000029000000ff0220018f00000005030000290000000803300210000007b803300197000000000223019f000007c701100197000000000112019f000000000014041b00000020010000390000010000100443000001200000044300000100010000390000004002000039000007c8030000411ebd03000000040f0002000000000002000200000006001d000100000005001d000007b105000041000007b10630009c00000000030580190000004003300210000007b10640009c00000000040580190000006004400210000000000334019f000007b10410009c0000000001058019000000c001100210000000000113019f1ebd1eb30000040f000000010900002900000000030100190000006003300270000007b1033001970000000205000029000000000453004b00000000050340190000001f0450018f00000005055002720000028c0000613d000000000600001900000005076002100000000008790019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002840000413d000000010220018f000000000640004c0000029c0000613d0000000505500210000000000651034f00000000055900190000000304400210000000000705043300000000074701cf000000000747022f000000000606043b0000010004400089000000000646022f00000000044601cf000000000474019f0000000000450435000100000003001f00030000000103550000000001020019000000000001042d0002000000000002000200000006001d000100000005001d000007b105000041000007b10630009c00000000030580190000004003300210000007b10640009c00000000040580190000006004400210000000000334019f000007b10410009c0000000001058019000000c001100210000000000113019f1ebd1eb80000040f000000010900002900000000030100190000006003300270000007b1033001970000000205000029000000000453004b00000000050340190000001f0450018f0000000505500272000002c30000613d000000000600001900000005076002100000000008790019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002bb0000413d000000010220018f000000000640004c000002d30000613d0000000505500210000000000651034f00000000055900190000000304400210000000000705043300000000074701cf000000000747022f000000000606043b0000010004400089000000000646022f00000000044601cf000000000474019f0000000000450435000100000003001f00030000000103550000000001020019000000000001042d000007b103000041000007b10410009c00000000010380190000004001100210000007b10420009c00000000020380190000006002200210000000000112019f0000000002000414000007b10420009c0000000002038019000000c002200210000000000112019f000007cc011001c700008010020000391ebd1eb80000040f0000000102200190000002eb0000613d000000000101043b000000000001042d000000000100001900000000020000191ebd030a0000040f0000000003010019000007b1010000410000000004000414000007b10540009c0000000001044019000000c00110021000000060022002100000000001120019000007cd0110004100000000020300191ebd1eb80000040f0000000102200190000002fd0000613d000000000101043b000000000001042d000000000100001900000000020000191ebd030a0000040f000007b104000041000007b10510009c000000000104801900000040011002100000000001310019000007b10320009c00000000020480190000006002200210000000000121001900001ebe0001042e000007b103000041000007b10420009c0000000002038019000007b10410009c000000000103801900000040011002100000006002200210000000000112019f00001ebf00010430000b0000000000020000008001000039000000400010043f0000000001000031000000040210008c000003a10000413d0000000202000367000000000302043b000000e003300270000007ce0430009c0000078d0000613d000007cf0430009c0000000005000411000003a80000613d000007d00430009c000007bd0000613d000007d10430009c000007fa0000613d000007d20430009c000003e70000613d000007d30430009c000003f50000613d000007d40430009c0000040d0000613d000007d50430009c0000043a0000613d000007d60430009c0000083b0000613d000007d70430009c000008530000613d000007d80430009c000004520000613d000007d90430009c000004730000613d000007da0430009c0000088c0000613d000007db0430009c000008a50000613d000007dc0430009c0000048c0000613d000007dd0430009c000008d50000613d000007de0430009c000008f20000613d000007df0430009c000004a40000613d000007e00430009c000004c80000613d000007e10430009c000005150000613d000007e20430009c0000052e0000613d000007e30430009c0000056e0000613d000007e40430009c0000090a0000613d000007e50430009c000009200000613d000007e60430009c000009380000613d000007e70430009c0000095c0000613d000007e80430009c0000000006000410000009830000613d000007e90430009c000005850000613d000007ea0430009c00000b040000613d000007eb0430009c0000059d0000613d000007ec0430009c000005bb0000613d000007ed0430009c00000b340000613d000007ee0430009c00000b4b0000613d000007ef0430009c00000b7c0000613d000007f00430009c00000b940000613d000007f10430009c00000be60000613d000007f20430009c00000c300000613d000007f30430009c00000c500000613d000007f40430009c000005d40000613d000007f50430009c000005f90000613d000007f60430009c000006110000613d000007f70430009c00000c860000613d000007f80430009c000006430000613d000007f90430009c0000065b0000613d000007fa0430009c00000cee0000613d000007fb0430009c000006920000613d000007fc0230009c00000d1a0000613d000007fd0230009c000006ba0000613d000007fe0230009c00000d6f0000613d000007ff0230009c00000d880000613d000008000230009c000006d80000613d000008010230009c0000071e0000613d000008020230009c000007570000613d000008030130009c00000fc20000c13d0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000000400100043d00000001020000390000000000210435000000200200003900000000030000191ebd03000000040f000000000110004c00000fc20000c13d1ebd11ce0000040f0000000001000019000000000200001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000400310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000002010003670000000402100370000000000202043b000a00000002001d000007b50220009c00000fc20000213d0000002401100370000000000101043b000900000001001d00000000005004350000000f01000039000000200010043f0000004002000039000800000002001d0000000001000019000b00000005001d1ebd02d70000040f0000000a020000290000000000200435000000200010043f000000000100001900000008020000291ebd02d70000040f0000000902000029000000000021041b000000400100043d0000000000210435000007b1020000410000000003000414000007b10430009c0000000003028019000007b10410009c00000000010280190000004001100210000000c002300210000000000112019f00000816011001c70000800d02000039000000030300003900000831040000410000000b050000290000000a060000291ebd1eb30000040f000000010120019000000fc20000613d0000039b0000013d000000040110008a000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000003a30000013d0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000801000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d1ebd11430000040f000000000100041a000900000001001d000000ff0110018f1ebd144c0000040f000001000100008a000a00000001001d0000000902000029000000000112016f000000000010041b1ebd17100000040f0000000b010000291ebd16ab0000040f000000000200041a0000000a03000029000000000232016f00000001022001bf000000000020041b000000400300043d00000000001304350000002002000039000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000d01000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d00000000010000311ebd11b20000040f000b00000001001d000a00000002001d000900000003001d000000000100041a000700000001001d000000ff0110018f1ebd144c0000040f000001000100008a000800000001001d0000000702000029000000000112016f000000000010041b00000000010004110000000b020000290000000a0300002900000009040000291ebd14640000040f000000000100041a0000000802000029000000000121016f00000001011001bf000000000010041b0000000102000039000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000401000039000000000101041a000007b502100197000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d1ebd16980000040f000000400300043d00000000001304350000002002000039000000000103001900000000030000191ebd03000000040f000000040110008a000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000000000100041a000a00000001001d000000ff0110018f1ebd144c0000040f000001000100008a000b00000001001d0000000a02000029000000000112016f000000000010041b1ebd17100000040f0000000003000416000000000100041100000000020100191ebd18b70000040f000000000100041a0000000b02000029000000000121016f00000001011001bf000000000010041b0000000001000019000000000200001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d000007b50110009c00000fc20000213d0000000b0100002900000000001004350000000e01000039000000200010043f0000004002000039000900000002001d00000000010000191ebd02d70000040f000000000101041a000a00000001001d0000001001000039000800000001001d000000200010043f000000000100001900000009020000291ebd02d70000040f0000000a040000290000000101100039000000000101041a000000000110004c00000000020000190000050e0000613d000000400200003900000000010000191ebd02d70000040f000000000101041a000007c4231000d1000000000210004c000004ff0000613d00000000211300d9000007c40110009c000007860000c13d000900000003001d0000000b0100002900000000001004350000000801000029000000200010043f000000400200003900000000010000191ebd02d70000040f0000000101100039000000000101041a000000000210004c0000068b0000613d000000090200002900000000121200d90000000a04000029000000400100043d000000200310003900000000002304350000000000410435000000400200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000501000039000000000101041a000007b502100197000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000900000001001d000000000100041a000a00000001001d000000ff0110018f000b00000005001d1ebd144c0000040f000001000100008a0000000a02000029000000000112016f000000000010041b1ebd17100000040f0000000b020000290000000303000039000000000103041a0000000801100270000007b501100197000000000112004b000005590000613d0000001201000039000000000101041a000007b501100197000000000112004b00000dd50000c13d000a00000003001d0000000901000039000000000101041a000b00000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000b02000029000000000112004b00000df10000c13d1ebd16980000040f0000000902000029000000000121004b00000e670000813d000000400100043d0000082f02000041000000000021043500000004020000391ebd030a0000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000000400100043d0000082b020000410000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000c01000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d1ebd11430000040f0000000b010000291ebd16ab0000040f000000400300043d00000000001304350000002002000039000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000001201000039000000000101041a000007b502100197000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000007b50210009c00000fc20000213d0000000302000039000000000202041a0000000802200270000007b502200197000000000225004b00000de70000c13d0000001202000039000000000302041a000007c003300197000000000113019f000000000012041b0000000001000019000000000200001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d1ebd16d10000040f000000400300043d00000000001304350000002002000039000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d1ebd11430000040f0000000b01000029000007b50110019700000000001004350000000e01000039000000200010043f000000400200003900000000010000191ebd02d70000040f000000000101041a000a00000001001d0000000b010000291ebd16ab0000040f000b00000001001d1ebd16e30000040f000000400300043d00000020023000390000000a04000029000000000042043500000040023000390000000b0400002900000000004204350000006002300039000000000012043500000000000304350000008002000039000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000001101000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f000a00000006001d0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000b00000005001d00000004010000390000000201100367000000000101043b000800000001001d000000000100041a000900000001001d000000ff0110018f1ebd144c0000040f000001000100008a000700000001001d0000000902000029000000000112016f000000000010041b1ebd17100000040f1ebd16e30000040f000000400400043d000008100340009c00000fe10000213d0000002003400039000000400030043f00000000001404350000000802000029000000000320004c00000df60000c13d000000000110004c00000000030000190000000b040000290000000a0500002900000dfd0000c13d000007c90100004100000000001004350000001201000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000040110008a000007b403000041000000200410008c00000000040000190000000004034019000007b401100197000000000510004c000000000300a019000007b40110009c00000000010400190000000001036019000000000110004c00000fc20000c13d0000000401200370000000000101043b000b00000001001d1ebd11430000040f000000000100041a000900000001001d000000ff0110018f1ebd144c0000040f000001000100008a000a00000001001d0000000902000029000000000112016f000000000010041b1ebd17100000040f000000000300041600000000010004110000000b020000291ebd18b70000040f000000000100041a0000000a02000029000000000121016f00000001011001bf000000000010041b0000000001000019000000000200001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d1ebd11430000040f1ebd17100000040f0000000b010000291ebd1de50000040f000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000601000039000000000101041a000b00000001001d1ebd16980000040f00000000020100190000000b01000039000000000601041a0000000c01000039000000000401041a000000400300043d0000080c01000041000000000013043500000044053000390000000001000414000000000045043500000024043000390000000000640435000000040430003900000000002404350000000b02000029000007b502200197000000040420008c000007080000613d000000640400003900000020060000390000000005030019000b00000003001d1ebd02a00000040f0000000b03000029000000000110004c00000e1a0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000007b60410009c00000fe10000213d000000010450019000000fe10000c13d000000400010043f000000200220008c00000fc20000413d00000000020304330000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000900000001001d000000000100041a000a00000001001d000000ff0110018f000b00000005001d1ebd144c0000040f000001000100008a0000000a02000029000000000112016f000000000010041b1ebd17100000040f0000000301000039000000000101041a0000000801100270000007b5011001970000000b02000029000000000112004b00000da90000c13d0000000901000039000000000101041a000b00000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000b02000029000000000112004b00000e620000c13d0000000904000029000008090140009c00000e700000413d000000400100043d0000080b02000041000000000021043500000004020000391ebd030a0000040f000000040110008a000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000b00000005001d000000000100041a000a00000001001d000000ff0110018f1ebd144c0000040f000001000100008a0000000a02000029000000000112016f000000000010041b1ebd17100000040f0000000901000039000000000101041a000a00000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000a02000029000000000112004b00000da20000c13d0000000002000416000a00000002001d0000000b010000291ebd18290000040f0000000a040000290000000c02000039000000000302041a0000000001430019000000000331004b00000000030000190000000103004039000000010330019000000dae0000613d000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000101000039000900000001001d000000000101041a000a00000001001d000000400200043d000b00000002001d1ebd10fb0000040f0000000a030000290000000b070000290000000000170435000000010230019000000dc80000c13d000001000200008a000000000223016f00000020037000390000000000230435000000000110004c00000020020000390000000002006019000000200220003900000000010700191ebd11190000040f000000400100043d000a00000001001d0000000b020000291ebd112d0000040f0000000a030000290000000002310049000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d0000000002000031000000040120008a000007b403000041000000e00410008c00000000040000190000000004034019000007b401100197000000000510004c000000000300a019000007b40110009c00000000010400190000000001036019000000000110004c00000fc20000c13d00000002010003670000000403100370000000000303043b000b00000003001d000007b50330009c00000fc20000213d0000002403100370000000000303043b000a00000003001d000007b50330009c00000fc20000213d0000006401100370000000000101043b000007b60310009c00000fc20000213d00000004011000391ebd11490000040f000900000001001d00000084010000390000000201100367000000000101043b000007b60210009c00000fc20000213d000000000200003100000004011000391ebd11490000040f00000000050100190000000201000367000000a402100370000000000602043b000000ff0260008c00000fc20000213d000000c402100370000000000702043b0000004401100370000000000301043b0000000b010000290000000a0200002900000009040000291ebd13420000040f0000000001000019000000000200001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000301000039000000000101041a0000000801100270000007b501100197000000000115004b000008160000613d0000001201000039000000000101041a000007b501100197000000000115004b00000dd50000c13d000b00000005001d1ebd17100000040f0000000c01000039000a00000001001d000000000201041a000000000001041b0000001201000039000000000101041a000007b5011001971ebd184e0000040f0000000a01000029000000000101041a000000400200043d000000200320003900000000001304350000000b01000029000007b501100197000000000012043500000040012000390000000000010435000007b1010000410000000003000414000007b10430009c0000000003018019000007b10420009c00000000010240190000004001100210000000c002300210000000000112019f00000805011001c70000800d0200003900000001030000390000082d040000411ebd1eb30000040f000000010120019000000fc20000613d0000091b0000013d0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d1ebd16e30000040f000000400300043d00000000001304350000002002000039000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d0000000003000031000000040130008a000007b402000041000000200410008c00000000040000190000000004024019000007b401100197000000000510004c000000000200a019000007b40110009c00000000010400190000000001026019000000000110004c00000fc20000c13d00000002020003670000000401200370000000000101043b000007b60410009c00000fc20000213d0000002304100039000007b405000041000000000634004b00000000060000190000000006058019000007b407300197000007b404400197000000000874004b0000000005008019000000000474013f000007b40440009c00000000040600190000000004056019000000000440004c00000fc20000c13d0000000404100039000000000242034f000000000202043b000007b60420009c00000fc20000213d000000240110003900000005042002100000000004140019000000000334004b00000fc20000213d1ebd15f00000040f0000000002010019000000400100043d000b00000001001d1ebd119a0000040f0000000b030000290000000002310049000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000301000039000000000101041a000000ff0210018f000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000a00000001001d1ebd11430000040f1ebd16d10000040f000900000001001d000000400100043d000b00000001001d1ebd110d0000040f0000000b01000029000000090200002900000000002104350000000a01000029000007b50110019700000000001004350000000e01000039000000200010043f000000400200003900000000010000191ebd02d70000040f000000000201041a0000000b010000291ebd1e780000040f0000000001010433000007c41210012a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d1ebd11430000040f0000000b010000291ebd1d630000040f000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000b01000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000901000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d1ebd11430000040f0000000b01000029000007b50110019700000000001004350000000e01000039000000200010043f000000400200003900000000010000191ebd02d70000040f000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000000000100041a000a00000001001d000000ff0110018f1ebd144c0000040f000001000100008a000b00000001001d0000000a02000029000000000112016f000000000010041b1ebd17100000040f000000000100041a0000000b02000029000000000121016f00000001011001bf0000000b02000039000000000202041a000000000010041b000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f000a00000006001d0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d000b00000005001d00000004010000390000000201100367000000000101043b000800000001001d000000000100041a000900000001001d000000ff0110018f1ebd144c0000040f000001000100008a000700000001001d0000000902000029000000000112016f000000000010041b1ebd17100000040f1ebd16e30000040f000000400200043d000008280320009c00000fe10000813d0000002003200039000000400030043f000000000012043500000008010000291ebd1e9a0000040f00000000040100190000000501000039000400000001001d000000000201041a000000400500043d0000081101000041000000000015043500000044035000390000000001000414000600000004001d00000000004304350000000b03000029000007b5043001970000002403500039000500000004001d00000000004304350000000a03000029000007b5043001970000000403500039000300000004001d0000000000430435000007b502200197000000040320008c000009ce0000613d000000640400003900000020060000390000000003050019000900000005001d00000009050000291ebd02690000040f0000000905000029000000000110004c00000e1a0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001530019000000000331004b00000000030000190000000103004039000007b60410009c00000fe10000213d000000010330019000000fe10000c13d000000400010043f000000200220008c00000fc20000413d0000000002050433000000000320004c00000ebb0000c13d0000000901000039000000000101041a000900000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000902000029000000000112004b00000ecc0000c13d1ebd16980000040f0000000802000029000000000121004b00000e5d0000413d0000000d01000039000000000201041a0000000603000029000000000332004b0000000b03000029000007860000413d00000006030000290000000002320049000000000021041b000000050100002900000000001004350000000e01000039000900000001001d000000200010043f0000004002000039000200000002001d00000000010000191ebd02d70000040f000000050200002900000000002004350000000902000029000000200020043f000100000001001d000000000100001900000002020000291ebd02d70000040f000000000101041a0000000602000029000000000221004b000007860000413d000000060200002900000000012100490000000102000029000000000012041b0000000b0100002900000008020000291ebd184e0000040f0000001201000039000000000101041a00000813020000410000000000200439000007b501100197000200000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d000008140100004100000000001404350000004402400039000000000100041400000006030000290000000000320435000000240240003900000005030000290000000000320435000100000004001d0000000402400039000008150300004100000000003204350000000202000029000000040220008c00000a3b0000613d000000640400003900000002020000290000000103000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000101000029000007b60110009c00000fe10000213d0000000104000029000000400040043f00000006010000290000000000140435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10340009c00000000010440190000004001100210000000c002200210000000000112019f00000816011001c70000800d02000039000000030300003900000817040000410000000b050000290000000a060000291ebd1eb30000040f000000010120019000000fc20000613d0000000401000029000000000101041a000b00000001001d000000050100002900000000001004350000000901000029000000200010043f000000400200003900000000010000191ebd02d70000040f000000000101041a000a00000001001d000008130100004100000000001004390000000b01000029000007b501100197000b00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d00000818010000410000000000140435000000440240003900000000010004140000000a030000290000000000320435000000240240003900000003030000290000000000320435000000040240003900000005030000290000000000320435000a00000004001d000000640240003900000000000204350000000b02000029000000040220008c00000a860000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000a01000029000007b60110009c00000fe10000213d0000000a01000029000000400010043f0000000401000029000000000101041a00000813020000410000000000200439000007b501100197000b00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d000008190100004100000000001404350000004402400039000000000100041400000006030000290000000000320435000000240240003900000008030000290000000000320435000a00000004001d0000000402400039000000050300002900000000003204350000000b02000029000000040220008c00000ab00000613d00000064040000390000000b020000290000000a03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000a01000029000007b60110009c00000fe10000213d0000000a04000029000000400040043f00000040014000390000000602000029000000000021043500000020014000390000000802000029000000000021043500000005010000290000000000140435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10340009c00000000010440190000004001100210000000c002200210000000000112019f00000805011001c70000800d0200003900000001030000390000081a040000411ebd1eb30000040f000000010120019000000fc20000613d0000000401000029000000000101041a00000813020000410000000000200439000007b501100197000b00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d0000081b0100004100000000001404350000006402400039000000000100041400000006030000290000000000320435000000440240003900000008030000290000000000320435000000240240003900000005030000290000000000320435000a00000004001d0000000402400039000000030300002900000000003204350000000b02000029000000040220008c00000af50000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000a01000029000007b60110009c00000fe10000213d0000000a01000029000000400010043f000000000100041a0000000702000029000000000121016f00000001011001bf000000000010041b000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000201000039000900000001001d000000000101041a000a00000001001d000000400200043d000b00000002001d1ebd10fb0000040f0000000a030000290000000b070000290000000000170435000000010230019000000dda0000c13d000001000200008a000000000223016f00000020037000390000000000230435000000000110004c00000020020000390000000002006019000000200220003900000000010700191ebd11190000040f000000400100043d000a00000001001d0000000b020000291ebd112d0000040f0000000a030000290000000002310049000000000103001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d1ebd17100000040f000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000400310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000b00000001001d1ebd11430000040f000000000100041a000900000001001d000000ff0110018f1ebd144c0000040f000001000100008a000a00000001001d0000000902000029000000000112016f000000000010041b00000024010000390000000201100367000000000401043b000000000100041100000000020100190000000b030000291ebd14640000040f000000000100041a0000000a02000029000000000121016f00000001011001bf000000000010041b0000000102000039000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000a01000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f000000040110008a000007b403000041000000400410008c00000000040000190000000004034019000007b401100197000000000510004c000000000300a019000007b40110009c00000000010400190000000001036019000000000110004c00000fc20000c13d0000000401200370000000000101043b000b00000001001d000007b50110009c00000fc20000213d0000002401200370000000000101043b000a00000001001d000007b50110009c00000fc20000213d000000000100041a000900000001001d000000ff0110018f1ebd144c0000040f000001000100008a000800000001001d0000000902000029000000000112016f000000000010041b1ebd17100000040f0000082501000041000000400300043d000000000013043500000000010004140000000a02000029000000040420008c00000bc40000613d00000004040000390000002006000039000900000003001d00000009050000291ebd02690000040f0000000903000029000000000110004c00000e1a0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000007b60410009c00000fe10000213d000000010450019000000fe10000c13d000000400010043f000000200220008c00000fc20000413d0000000002030433000000000320004c00000ec10000c13d000000000300041600000000010004110000000b020000290000000a040000291ebd19f30000040f000000000100041a0000000802000029000000000121016f00000001011001bf000000000010041b0000000001000019000000000200001900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000601000039000000000101041a000b00000001001d1ebd16980000040f00000000020100190000000b01000039000000000701041a0000000c01000039000000000401041a0000000801000039000000000501041a000000400300043d000008240100004100000000001304350000006406300039000000000100041400000000005604350000004405300039000000000045043500000024043000390000000000740435000000040430003900000000002404350000000b02000029000007b502200197000000040420008c00000c1a0000613d000000840400003900000020060000390000000005030019000b00000003001d1ebd02a00000040f0000000b03000029000000000110004c00000e1a0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000007b60410009c00000fe10000213d000000010450019000000fe10000c13d000000400010043f000000200220008c00000fc20000413d00000000020304330000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d00000000010000311ebd11b20000040f000b00000001001d000a00000002001d000900000003001d000000000100041a000700000001001d000000ff0110018f1ebd144c0000040f000001000100008a000800000001001d0000000702000029000000000112016f000000000010041b00000000010004110000000b020000290000000a0300002900000009040000291ebd1b9d0000040f000000000100041a0000000802000029000000000121016f00000001011001bf000000000010041b000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004020000390000000201200367000000000101043b000007b50310009c00000fc20000213d0000000303000039000000000303041a0000000803300270000007b503300197000000000335004b00000de70000c13d000000000302041a000007c004300197000000000414019f000000000042041b000000400200043d00000020042000390000000000140435000007b5013001970000000000120435000007b1010000410000000003000414000007b10430009c0000000003018019000007b10420009c00000000010240190000004001100210000000c002300210000000000112019f000007c1011001c70000800d0200003900000001030000390000080e040000411ebd1eb30000040f00000001012001900000091b0000c13d00000fc20000013d000a00000006001d0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000200310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d00000004010000390000000201100367000000000101043b000900000001001d000000000100041a000800000001001d000000ff0110018f000b00000005001d1ebd144c0000040f000001000100008a000700000001001d0000000802000029000000000112016f000000000010041b1ebd17100000040f00000009050000290000000501000039000800000001001d000000000201041a0000081c01000041000000400300043d00000000001304350000000a01000029000007b506100197000000040430003900000000010004140000000000640435000000440430003900000000005404350000000b04000029000007b5044001970000002406300039000a00000004001d0000000000460435000007b502200197000000040420008c00000cc60000613d000000640400003900000020060000390000000005030019000600000003001d1ebd02690000040f00000006030000290000000905000029000000000110004c00000e1a0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000060000190000000106004039000007b60410009c00000fe10000213d000000010460019000000fe10000c13d000000400010043f000000200220008c00000fc20000413d0000000002030433000000000320004c00000e880000c13d0000000901000039000000000101041a000600000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000602000029000000000112004b00000ec70000c13d1ebd16980000040f0000000902000029000000000121004b00000ed70000813d000000400100043d0000082202000041000000000021043500000004020000391ebd030a0000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000400310008c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000201000367000b0000000103530000000401100370000000000101043b000a00000001001d1ebd11430000040f0000000b0100035f0000002401100370000000000101043b000b00000001001d1ebd11430000040f0000000a01000029000007b50110019700000000001004350000000f01000039000000200010043f000000400200003900000000010000191ebd02d70000040f0000000b020000291ebd145d0000040f000000000201041a000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000406000039000000000106041a000007b501100197000000000115004b00000dec0000c13d000000000150004c00000dec0000613d00000008015002100000000302000039000000000302041a000007b704300197000000000114019f000000000012041b000000000106041a000007c001100197000a00000006001d000000000016041b000000000102041a0000000801100270000007b501100197000000400200043d000000200420003900000000001404350000000801300270000007b5011001970000000000120435000007b1010000410000000003000414000007b10430009c0000000003018019000007b10420009c00000000010240190000004001100210000000c002300210000000000112019f000007c1011001c70000800d0200003900000001030000390000080d04000041000b00000005001d1ebd1eb30000040f0000000b04000029000000010120019000000fc20000613d0000000a01000029000000000101041a000007b501100197000000400200043d000000200320003900000000001304350000000000420435000007b1010000410000000003000414000007b10430009c0000000003018019000007b10420009c00000000010240190000004001100210000000c002300210000000000112019f000007c1011001c70000800d0200003900000001030000390000080e040000411ebd1eb30000040f00000001012001900000091b0000c13d00000fc20000013d0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000601000039000000000101041a000007b502100197000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f0000000001000416000000000110004c00000fc20000c13d000000040100008a0000000001100031000007b402000041000000000310004c00000000030000190000000003024019000007b401100197000000000410004c000000000200a019000007b40110009c00000000010300190000000001026019000000000110004c00000fc20000c13d0000000301000039000000000101041a0000000801100270000007b502100197000000400100043d0000000000210435000000200200003900000000030000191ebd03000000040f000000400100043d000008040200004100000000002104350000000402100039000000000002043500000024020000391ebd030a0000040f000000400100043d0000080702000041000000000021043500000004020000391ebd030a0000040f000000000012041b000000400200043d00000040032000390000000000130435000000200120003900000000004104350000000b01000029000007b5011001970000000000120435000007b1010000410000000003000414000007b10430009c0000000003018019000007b10420009c00000000010240190000004001100210000000c002300210000000000112019f00000805011001c70000800d02000039000000010300003900000806040000411ebd1eb30000040f000000010120019000000eb10000c13d00000fc20000013d00000009020000290000000000200435000008320300004100000020047000390000000002000019000000000512004b000007b10000813d0000000005240019000000000603041a00000000006504350000002002200039000000010330003900000dcd0000013d000000400100043d0000083002000041000000000021043500000004020000391ebd030a0000040f00000009020000290000000000200435000008270300004100000020047000390000000002000019000000000512004b00000b280000813d0000000005240019000000000603041a00000000006504350000002002200039000000010330003900000ddf0000013d000000400100043d0000082302000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000080f02000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000082c02000041000000000021043500000004020000391ebd030a0000040f00000000010400191ebd1e780000040f00000008020000290000000001010433000007c41310012a0000000b040000290000000a05000029000900000003001d0000000501000039000500000001001d000000000601041a000000400300043d00000811010000410000000000130435000000440730003900000000010004140000000000270435000007b5024001970000002404300039000600000002001d0000000000240435000007b5025001970000000404300039000400000002001d0000000000240435000007b502600197000000040420008c00000e3a0000613d000000640400003900000020060000390000000005030019000300000003001d1ebd02690000040f0000000303000029000000000110004c00000e3a0000c13d0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200000e290000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00000e210000413d000000000530004c00000e380000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000007b60410009c00000fe10000213d000000010450019000000fe10000c13d000000400010043f000000200220008c00000fc20000413d0000000002030433000000000320004c00000ed10000c13d0000000901000039000000000101041a000300000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000302000029000000000112004b00000ecc0000c13d1ebd16980000040f0000000902000029000000000121004b00000f910000813d000000400100043d0000082a02000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000080802000041000000000021043500000004020000391ebd030a0000040f0000000c01000039000000000401041a000000000324004b00000e8e0000813d000000400100043d0000082e02000041000000000021043500000004020000391ebd030a0000040f0000000801000039000000000201041a000000000041041b000000400100043d000000200310003900000000004304350000000000210435000007b1020000410000000003000414000007b10430009c0000000003028019000007b10410009c00000000010280190000004001100210000000c002300210000000000112019f000007c1011001c70000800d0200003900000001030000390000080a040000411ebd1eb30000040f000000010120019000000eb10000c13d00000fc20000013d0000081d0300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f0000000003240049000b00000003001d000000000031041b0000001201000039000000000101041a000007b5011001971ebd184e0000040f0000000a01000029000000000101041a000000400200043d00000040032000390000000b0400002900000000004304350000002003200039000000090400002900000000004304350000000801100270000007b5011001970000000000120435000007b1010000410000000003000414000007b10430009c0000000003018019000007b10420009c00000000010240190000004001100210000000c002300210000000000112019f00000805011001c70000800d0200003900000001030000390000082d040000411ebd1eb30000040f000000010120019000000fc20000613d000001000100008a000000000200041a000000000112016f00000001011001bf000000000010041b000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f000008120300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f000008260300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f000000400100043d0000081e02000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000082902000041000000000021043500000004020000391ebd030a0000040f000008120300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f0000000b010000291ebd16ab0000040f00000009020000290000000002210019000600000002001d000000000112004b000000000100001900000001010040390000000101100190000007860000c13d0000000b01000039000400000001001d000000000101041a00000009020000290000000002210019000500000002001d000000000112004b000000000100001900000001010040390000000101100190000007860000c13d0000000a0100002900000000001004350000001001000039000300000001001d000000200010043f0000004002000039000200000002001d00000000010000191ebd02d70000040f0000000602000029000000000021041b0000000a0100002900000000001004350000000301000029000000200010043f000000000100001900000002020000291ebd02d70000040f0000000a02000039000300000002001d000000000202041a0000000101100039000000000021041b00000005010000290000000402000029000000000012041b0000000b0100002900000009020000291ebd184e0000040f0000000903000029000007c4123000d1000b00000002001d0000001201000039000000000101041a000007b501100197000400000001001d000000000130004c00000f170000613d00000009010000290000000b0200002900000000211200d9000007c40110009c000007860000c13d0000000301000029000000000101041a000200000001001d000000000110004c0000068b0000613d0000081301000041000000000010043900000004010000290000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d0000081f0100004100000000001404350000000b01000029000000020200002900000000122100d900000044034000390000000001000414000000000023043500000024024000390000000a030000290000000000320435000b00000004001d0000000402400039000008200300004100000000003204350000000402000029000000040220008c00000f400000613d000000640400003900000004020000290000000b03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000b01000029000007b60110009c00000fe10000213d0000000b01000029000000400010043f0000000602000029000007c4132000d1000b00000003001d0000000801000029000000000101041a000007b501100197000800000001001d000000000120004c00000f530000613d00000006010000290000000b0200002900000000211200d9000007c40110009c000007860000c13d0000000301000029000000000101041a000400000001001d000000000110004c0000068b0000613d0000081301000041000000000010043900000008010000290000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d000008210100004100000000001404350000000b01000029000000040200002900000000122100d9000000840340003900000000010004140000000000230435000000640240003900000005030000290000000000320435000000440240003900000006030000290000000000320435000000240240003900000009030000290000000000320435000b00000004001d00000004024000390000000a0300002900000000003204350000000802000029000000040220008c00000f820000613d000000a40400003900000008020000290000000b03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000b01000029000007b60110009c00000fe10000213d0000000b01000029000000400010043f000000000100041a0000000702000029000000000121016f00000001011001bf000000000010041b000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000000d01000039000000000201041a0000000803000029000000000332004b0000000b03000029000007860000413d00000008030000290000000002320049000000000021041b000000060100002900000000001004350000000e01000039000300000001001d000000200010043f0000004002000039000200000002001d00000000010000191ebd02d70000040f000000060200002900000000002004350000000302000029000000200020043f000100000001001d000000000100001900000002020000291ebd02d70000040f000000000101041a0000000802000029000000000221004b000007860000413d000000080200002900000000012100490000000102000029000000000012041b0000000b0100002900000009020000291ebd184e0000040f0000001201000039000000000101041a00000813020000410000000000200439000007b501100197000200000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc50000c13d000000000100001900000000020000191ebd030a0000040f000000400400043d000008140100004100000000001404350000004402400039000000000100041400000008030000290000000000320435000000240240003900000006030000290000000000320435000100000004001d0000000402400039000008150300004100000000003204350000000202000029000000040220008c00000fde0000613d000000640400003900000002020000290000000103000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000101000029000007b60110009c00000fe80000a13d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000104000029000000400040043f00000008010000290000000000140435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10340009c00000000010440190000004001100210000000c002200210000000000112019f00000816011001c70000800d02000039000000030300003900000817040000410000000b050000290000000a060000291ebd1eb30000040f000000010120019000000fc20000613d0000000501000029000000000101041a000b00000001001d000000060100002900000000001004350000000301000029000000200010043f000000400200003900000000010000191ebd02d70000040f000000000101041a000a00000001001d000008130100004100000000001004390000000b01000029000007b501100197000b00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d00000818010000410000000000140435000000440240003900000000010004140000000a030000290000000000320435000000240240003900000004030000290000000000320435000000040240003900000006030000290000000000320435000a00000004001d000000640240003900000000000204350000000b02000029000000040220008c000010300000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000a01000029000007b60110009c00000fe10000213d0000000a01000029000000400010043f0000000501000029000000000101041a00000813020000410000000000200439000007b501100197000b00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d000008190100004100000000001404350000004402400039000000000100041400000008030000290000000000320435000000240240003900000009030000290000000000320435000a00000004001d0000000402400039000000060300002900000000003204350000000b02000029000000040220008c0000105a0000613d00000064040000390000000b020000290000000a03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000a01000029000007b60110009c00000fe10000213d0000000a04000029000000400040043f00000040014000390000000802000029000000000021043500000020014000390000000902000029000000000021043500000006010000290000000000140435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10340009c00000000010440190000004001100210000000c002200210000000000112019f00000805011001c70000800d0200003900000001030000390000081a040000411ebd1eb30000040f000000010120019000000fc20000613d0000000501000029000000000101041a00000813020000410000000000200439000007b501100197000b00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00000fc20000613d000000400400043d0000081b0100004100000000001404350000006402400039000000000100041400000008030000290000000000320435000000440240003900000009030000290000000000320435000000240240003900000006030000290000000000320435000a00000004001d0000000402400039000000040300002900000000003204350000000b02000029000000040220008c0000109f0000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000191ebd02690000040f000000000110004c00000e1a0000613d0000000a01000029000007b60110009c00000fe10000213d0000000a01000029000000400010043f000000000100041a0000000702000029000000000121016f00000001011001bf000000000010041b000000400100043d0000000000010435000000200200003900000000030000191ebd03000000040f0000001f03100039000007b404000041000000000523004b00000000050000190000000005044019000007b406200197000007b403300197000000000763004b000000000400a019000000000363013f000007b40330009c00000000030500190000000003046019000000000330004c000010e70000613d0000000004010433000008330340009c000010e00000813d0000003f03400039000000200500008a000000000553016f000000400300043d0000000005530019000000000635004b00000000060000190000000106004039000007b60750009c000010e00000213d0000000106600190000010e00000c13d000000400050043f000000000043043500000000054100190000002005500039000000000225004b000010e70000213d0000000002000019000000000542004b000010db0000813d00000020022000390000000005320019000000000612001900000000060604330000000000650435000010d30000013d0000000001340019000000200110003900000000000104350000000001030019000000000001042d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000000100001900000000020000191ebd030a0000040f000000000110004c000010ed0000613d000000000001042d000000400100043d00000044021000390000083403000041000000000032043500000024021000390000001c030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f000000010210019000000001011002700000007f0310018f00000000010360190000001f0310008c00000000030000190000000103002039000000010330018f000000000232004b000011060000c13d000000000001042d000007c90100004100000000001004350000002201000039000000040010043f000000240200003900000000010000191ebd030a0000040f000008280210009c000011120000813d0000002001100039000000400010043f000000000001042d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000001f02200039000000200300008a000000000232016f0000000001120019000000000221004b00000000020000190000000102004039000007b60310009c000011260000213d0000000102200190000011260000c13d000000400010043f000000000001042d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000002003000039000000000031043500000000030204330000002004100039000000000034043500000040011000390000000004000019000000000534004b0000113c0000813d00000000054100190000002004400039000000000624001900000000060604330000000000650435000011340000013d000000000231001900000000000204350000001f02300039000000200300008a000000000232016f0000000001210019000000000001042d000007b90110009c000011460000813d000000000001042d000000000100001900000000020000191ebd030a0000040f00000000030100190000001f01300039000007b404000041000000000521004b00000000050000190000000005044019000007b406200197000007b401100197000000000761004b000000000400a019000000000161013f000007b40110009c00000000010500190000000001046019000000000110004c000011970000613d0000000201300367000000000401043b000008330140009c000011900000813d0000003f01400039000000200500008a000000000551016f000000400100043d0000000005510019000000000615004b00000000060000190000000106004039000007b60750009c000011900000213d0000000106600190000011900000c13d000000400050043f000000000041043500000020033000390000000005430019000000000225004b000011970000213d0000001f0240018f0000000205300367000000200310003900000005064002720000117d0000613d000000000700001900000005087002100000000009830019000000000885034f000000000808043b00000000008904350000000107700039000000000867004b000011750000413d000000000720004c0000118c0000613d0000000506600210000000000565034f00000000036300190000000302200210000000000603043300000000062601cf000000000626022f000000000505043b0000010002200089000000000525022f00000000022501cf000000000262019f0000000000230435000000000214001900000020022000390000000000020435000000000001042d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000000100001900000000020000191ebd030a0000040f0000002003000039000000000031043500000020041000390000000003020433000000000034043500000000040000190000004001100039000000000534004b000011b10000813d0000002002200039000000000502043300000000060100190000000007000019000000010870008c000011af0000213d00000000080504330000000000860435000000010770003900000020055000390000002006600039000011a70000013d0000000104400039000011a00000013d000000000001042d000000040110008a000007b4020000410000005f0310008c00000000030000190000000003022019000007b401100197000000000410004c0000000002008019000007b40110009c00000000010300190000000001026019000000000110004c000011cb0000613d00000002030003670000000401300370000000000101043b000007b50210009c000011cb0000213d0000002402300370000000000202043b000007b50420009c000011cb0000213d0000004403300370000000000303043b000000000001042d000000000100001900000000020000191ebd030a0000040f000b000000000002000000000100041a000b00000001001d000000ff0110018f1ebd144c0000040f000001000100008a000100000001001d0000000b02000029000000000112016f000000000010041b1ebd17100000040f0000000501000039000700000001001d000000000201041a000000400500043d0000083501000041000000000015043500000044035000390000000001000414000000000400041600000000004304350000000003000411000800000003001d000007b5043001970000002403500039000b00000004001d00000000004304350000000003000410000400000003001d000007b5043001970000000403500039000200000004001d0000000000430435000007b502200197000000040320008c000011fb0000613d000000640400003900000020060000390000000003050019000a00000005001d0000000a050000291ebd02690000040f0000000a05000029000000000110004c000013170000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001530019000000000331004b00000000030000190000000103004039000007b60410009c000013090000213d0000000103300190000013090000c13d000000400010043f0000001f0220008c000013060000a13d0000000002050433000000000320004c000013370000c13d0000000901000039000000000101041a000a00000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000a02000029000000000112004b0000133d0000c13d1ebd16e30000040f000000400300043d000008100230009c000013090000213d0000002002300039000000400020043f00000000001304350000000002000416000900000002001d0000000801000029000a00000003001d1ebd18290000040f00000009010000290000000a020000291ebd1e9a0000040f00000000040100190000000d01000039000000000301041a0000000002430019000000000332004b000000000300001900000001030040390000000103300190000013100000c13d000000000021041b0000000b0100002900000000001004350000000e01000039000600000001001d000000200010043f0000004002000039000500000002001d0000000001000019000a00000004001d1ebd02d70000040f0000000b0200002900000000002004350000000602000029000000200020043f000300000001001d000000000100001900000005020000291ebd02d70000040f0000000a03000029000000000201041a0000000001320019000000000221004b000000000200001900000001020040390000000102200190000013100000c13d0000000302000029000000000012041b0000001201000039000000000101041a00000813020000410000000000200439000007b501100197000500000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c000013060000613d000000400500043d0000081f010000410000000000150435000000440250003900000000010004140000000a04000029000000000042043500000024025000390000000b0300002900000000003204350000000402500039000008150300004100000000003204350000000502000029000000040320008c000012750000613d00000064040000390000000003050019000500000005001d000000050500002900000000060000191ebd02690000040f00000005050000290000000a04000029000000000110004c000013170000613d000007b60150009c000013090000213d000000400050043f000000400150003900000000004104350000002001500039000000090200002900000000002104350000000b010000290000000000150435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10350009c00000000010540190000004001100210000000c002200210000000000112019f00000805011001c70000800d02000039000000010300003900000838040000411ebd1eb30000040f0000000101200190000013060000613d0000000701000029000000000101041a00000813020000410000000000200439000007b501100197000500000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c000013060000613d000000400500043d00000839010000410000000000150435000000440250003900000000010004140000000a04000029000000000042043500000024025000390000000903000029000000000032043500000004025000390000000b0300002900000000003204350000000502000029000000040320008c000012b50000613d00000064040000390000000003050019000900000005001d000000090500002900000000060000191ebd02690000040f00000009050000290000000a04000029000000000110004c000013170000613d000007b60150009c000013090000213d000000400050043f0000000000450435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10350009c00000000010540190000004001100210000000c002200210000000000112019f00000816011001c70000800d0200003900000003030000390000081704000041000000040500002900000008060000291ebd1eb30000040f0000000101200190000013060000613d0000000701000029000000000101041a000a00000001001d0000000b0100002900000000001004350000000601000029000000200010043f000000400200003900000000010000191ebd02d70000040f000000000101041a000900000001001d000008130100004100000000001004390000000a01000029000007b501100197000a00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c000013060000613d000000400500043d00000818010000410000000000150435000000640250003900000000010004140000000903000029000000000032043500000024025000390000000b030000290000000000320435000000040250003900000002030000290000000000320435000000440250003900000000000204350000000a02000029000000040320008c000012fd0000613d00000084040000390000000003050019000b00000005001d0000000b0500002900000000060000191ebd02690000040f0000000b05000029000000000110004c000013170000613d000007b60150009c000013090000213d000000400050043f000000000100041a0000000102000029000000000121016f00000001011001bf000000000010041b000000000001042d000000000100001900000000020000191ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000013260000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b0000131e0000413d000000000530004c000013350000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f000008360300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f000000400100043d0000083702000041000000000021043500000004020000391ebd030a0000040f00080000000000020000000308000039000000000908041a0000000809900270000007b50a90019700000000090004110000000009a9004b0000142a0000c13d000000090a00003900000000090a041a000000000990004c000014120000c13d0000000a0b00003900000000090b041a000000000990004c000014120000c13d00040000000b001d00050000000a001d000600000002001d000800000004001d000700000005001d000100000008001d000200000006001d000300000007001d0000000702000039000000000032041b000000000202041a000000000220004c0000143b0000613d1ebd1d630000040f000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000502000029000000000012041b000007c4010000410000000402000029000000000012041b00000006010000291ebd1de50000040f00000008010000290000000001010433000500000001001d000008330110009c000014230000813d0000000101000039000600000001001d000000000101041a1ebd10fb0000040f000000200210008c0000000509000029000013880000413d0000001f02900039000000050220027000000832022000410000083203000041000000200490008c0000000002034019000000010300003900000000003004350000001f0110003900000005011002700000083201100041000000000312004b000013880000813d000000000002041b0000000102200039000013830000013d000000200190008c0000139c0000413d00000001010000390000000000100435000000200200008a000000000329016f00000832020000410000002004000039000000000500001900000007070000290000000808000029000000000635004b0000000006840019000013aa0000813d0000000006060433000000000062041b000000200550003900000020044000390000000102200039000013930000013d000000000190004c00000000010000190000000802000029000013a20000613d000000200120003900000000010104330000000302900210000000010300008a000000000223022f000000000232013f000000000221016f00000001019002100000000707000029000013b50000013d000000000393004b000013b40000813d0000000303900210000000f80330018f000000010400008a000000000334022f000000000343013f0000000004060433000000000334016f000000000032041b0000000102900210000000000112019f0000000602000029000000000012041b0000000001070433000500000001001d000007b60110009c000014230000213d0000000201000039000800000001001d000000000101041a1ebd10fb0000040f000000200210008c000000030600002900000001070000290000000509000029000013d50000413d0000001f02900039000000050220027000000827022000410000082703000041000000200490008c0000000002034019000000080300002900000000003004350000001f0110003900000005011002700000082701100041000000000312004b000013d50000813d000000000002041b0000000102200039000013d00000013d000000200190008c000013e80000413d00000008010000290000000000100435000000200100008a000000000219016f0000082701000041000000200300003900000000040000190000000708000029000000000524004b0000000005830019000013f50000813d0000000005050433000000000051041b000000200440003900000020033000390000000101100039000013df0000013d000000000190004c00000000010000190000000702000029000013ee0000613d000000200120003900000000010104330000000302900210000000010300008a000000000223022f000000000232013f000000000121016f0000000102900210000014010000013d000000000292004b000013ff0000813d0000000302900210000000f80220018f000000010300008a000000000223022f000000000232013f0000000003050433000000000223016f000000000021041b00000001019002100000000602000029000000000121019f0000000802000029000000000012041b000000000107041a000001000200008a000000000121016f0000000203000029000000ff0330018f000000000131019f000000000017041b0000001101000039000000000061041b000000000100041a000000000121016f00000001011001bf000000000010041b000000000001042d000000400100043d0000006402100039000007bd0300004100000000003204350000004402100039000007be030000410000000000320435000000240210003900000023030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000084020000391ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000400100043d0000006402100039000007ba0300004100000000003204350000004402100039000007bb030000410000000000320435000000240210003900000024030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000084020000391ebd030a0000040f000000400100043d0000006402100039000007ca0300004100000000003204350000004402100039000007cb030000410000000000320435000000240210003900000030030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000084020000391ebd030a0000040f000000000110004c0000144f0000613d000000000001042d000000400100043d00000044021000390000083a03000041000000000032043500000024021000390000000a030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f000007b5022001970000000000200435000000200010043f000000400200003900000000010000191ebd02d70000040f000000000001042d000c00000000000200000000070100190000000501000039000300000001001d000000000601041a000000400800043d000000640180003900000000004104350000083b0100004100000000001804350000000001000410000007b50110019700000004058000390000000000150435000007b5033001970000004401800039000800000003001d0000000000310435000007b5022001970000002401800039000a00000002001d00000000002104350000000001000414000007b502600197000000040320008c000900000004001d0000148b0000613d0000008404000039000000200600003900000000030800190000000005080019000700000007001d000600000008001d1ebd02690000040f000000060800002900000007070000290000000904000029000000000110004c000015c60000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001830019000000000331004b00000000030000190000000103004039000007b60510009c000015b80000213d0000000103300190000015b80000c13d000000400010043f0000001f0220008c000015b50000a13d0000000002080433000000000320004c000015e60000c13d00000008020000290000000a03000029000000000223004b000015ec0000613d000000010100008a000600000001001d00000000020004150000000c0220008a00000020022000c9000007b501700197000500000001001d000000000131004b000014c20000613d0000000a0100002900000000001004350000000f01000039000000200010043f0000004002000039000700000002001d00000000010000191ebd02d70000040f00000005020000290000000000200435000000200010043f000000000100001900000007020000291ebd02d70000040f000000090400002900000000020004150000000b0220008a00000020022000c9000000000101041a000600000001001d000000000141004b000015bf0000413d000000200120011a000000060200002900000000014200550000000a0100002900000000001004350000000e01000039000700000001001d000000200010043f000000400200003900000000010000191ebd02d70000040f000000000201041a0000000901000029000400000002001d000000000112004b000015bf0000413d000000080100002900000000001004350000000701000029000000200010043f000000400200003900000000010000191ebd02d70000040f0000000903000029000000000101041a0000000002310019000200000002001d000000000112004b000000000100001900000001010040390000000101100190000015bf0000c13d0000000a0100002900000000001004350000000701000029000000200010043f0000004002000039000100000002001d00000000010000191ebd02d70000040f000000090300002900000004020000290000000002320049000000000021041b000000080100002900000000001004350000000701000029000000200010043f000000000100001900000001020000291ebd02d70000040f0000000202000029000000000021041b000000010100008a0000000602000029000000000112004b00000000010200190000150f0000613d00000009020000290000000001210049000600000001001d0000000a0100002900000000001004350000000f01000039000000200010043f0000004002000039000400000002001d00000000010000191ebd02d70000040f00000005020000290000000000200435000000200010043f000000000100001900000004020000291ebd02d70000040f0000000602000029000000000021041b0000001201000039000500000001001d000000000101041a00000813020000410000000000200439000007b501100197000600000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c0000000903000029000015b50000613d000000400500043d0000081401000041000000000015043500000044025000390000000001000414000000000032043500000024025000390000000a0300002900000000003204350000000402500039000008150300004100000000003204350000000602000029000000040320008c000015350000613d00000064040000390000000003050019000600000005001d000000060500002900000000060000191ebd02690000040f0000000605000029000000000110004c000015c60000613d000007b60150009c000015b80000213d000000400050043f0000000501000029000000000101041a00000813020000410000000000200439000007b501100197000600000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f0000000904000029000000000110004c000015b50000613d000000400500043d0000081f0100004100000000001504350000004402500039000000000100041400000000004204350000002402500039000000080300002900000000003204350000000402500039000008150300004100000000003204350000000602000029000000040320008c0000155e0000613d00000064040000390000000003050019000600000005001d000000060500002900000000060000191ebd02690000040f00000006050000290000000904000029000000000110004c000015c60000613d000007b60150009c000015b80000213d000000400050043f0000000000450435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10350009c00000000010540190000004001100210000000c002200210000000000112019f00000816011001c70000800d02000039000000030300003900000817040000410000000a0500002900000008060000291ebd1eb30000040f0000000101200190000015b50000613d0000000301000029000000000101041a000900000001001d0000000a0100002900000000001004350000000701000029000000200010043f0000004002000039000600000002001d00000000010000191ebd02d70000040f000000000101041a000500000001001d000000080100002900000000001004350000000701000029000000200010043f000000000100001900000006020000291ebd02d70000040f000000000101041a000700000001001d000008130100004100000000001004390000000901000029000007b501100197000900000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c000015b50000613d000000400500043d00000818010000410000000000150435000000640250003900000000010004140000000703000029000000000032043500000044025000390000000503000029000000000032043500000024025000390000000803000029000000000032043500000004025000390000000a0300002900000000003204350000000902000029000000040320008c000015b10000613d00000084040000390000000003050019000a00000005001d0000000a0500002900000000060000191ebd02690000040f0000000a05000029000000000110004c000015c60000613d000007b60150009c000015b80000213d000000400050043f000000000001042d000000000100001900000000020000191ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000015d50000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000015cd0000413d000000000530004c000015e40000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f0000083c0300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f0000083d02000041000000000021043500000004020000391ebd030a0000040f000b000000000002000400000001001d000500000002001d000008330120009c000016800000813d000000050100002900000005011002100000003f02100039000000200300008a000000000232016f000000400800043d0000000002280019000000000382004b00000000030000190000000103004039000007b60420009c000016800000213d0000000103300190000016800000c13d000000400020043f0000000502000029000000000028043500000020098000390000000002000019000000000312004b0000161e0000813d000000400300043d0000083e0430009c000016800000213d0000004004300039000000400040043f00000000040000310000000204400367000000000500001900000005065002100000000007630019000000000664034f000000000606043b00000000006704350000000105500039000000020650008c000016120000413d000000000429001900000000003404350000002002200039000016080000013d0000000e01000039000300000001001d0000004001000039000900000001001d0000001001000039000a00000001001d0000000003000019000200000008001d000100000009001d0000000501000029000000000113004b000016770000813d0000000501300210000000040200002900000000022100190000000202200367000000000402043b000007b90240009c000016870000813d0000000002080433000000000232004b000016790000a13d000700000003001d0000000001190019000600000001001d0000000001010433000800000001001d00000000004004350000000301000029000000200010043f00000000010000190000000902000029000b00000004001d1ebd02d70000040f000000000101041a000000080200002900000000001204350000000b0100002900000000001004350000000a01000029000000200010043f000000000100001900000009020000291ebd02d70000040f0000000101100039000000000101041a000000000110004c00000000010000190000166b0000613d0000000b0100002900000000001004350000000a01000029000000200010043f000000400200003900000000010000191ebd02d70000040f000000000101041a000007c4231000d1000000000210004c0000165d0000613d00000000211300d9000007c40110009c000016910000c13d000800000003001d0000000b0100002900000000001004350000000a01000029000000200010043f000000400200003900000000010000191ebd02d70000040f0000000101100039000000000101041a000000000210004c0000168a0000613d000000080200002900000000211200d9000000020800002900000000020804330000000703000029000000000232004b0000000109000029000016790000a13d00000006020000290000000002020433000000200220003900000000001204350000000103300039000016270000013d0000000001080019000000000001042d000007c90100004100000000001004350000003201000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000000100001900000000020000191ebd030a0000040f000007c90100004100000000001004350000001201000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000083f010000410000000000100439000000000100041000000004001004430000800a0100003900000024020000391ebd02ee0000040f0000000002000416000000000321004b000016a40000413d0000000001210049000000000001042d000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007b50110019700000000001004350000001001000039000000200010043f000000400200003900000000010000191ebd02d70000040f000000000301041a000000000230004c0000000002000019000016c10000613d0000000a02000039000000000402041a00000000523400a900000000533200d9000000000343004b000016c30000c13d0000000101100039000000000101041a000000000310004c000016ca0000613d00000000121200d90000000001020019000000000001042d000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000001201000039000000040010043f000000240200003900000000010000191ebd030a0000040f0002000000000002000000000100041a000100000001001d000000ff0110018f1ebd144c0000040f000001000100008a000200000001001d0000000102000029000000000112016f000000000010041b1ebd17100000040f1ebd16e30000040f000000000200041a0000000203000029000000000232016f00000001022001bf000000000020041b000000000001042d00010000000000020000000d01000039000000000201041a000000000120004c000017060000613d000100000002001d1ebd16980000040f0000000b02000039000000000202041a0000000001120019000000000221004b000000000200001900000001020040390000000102200190000017090000c13d0000000c02000039000000000302041a000000000231004b000017090000413d00000000053100490000000104000039000007c4625000d1000000000631004b000016ff0000613d00000000545200d9000007c40440009c0000000004000019000000010400c039000000000131004b000017030000613d0000000101400190000017090000c13d000000010100002900000000211200d9000017080000013d0000000701000039000000000101041a000000000001042d000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f00090000000000020000000901000039000800000001001d000000000101041a000900000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000902000029000000000112004b000017ea0000613d1ebd16980000040f00000000020100190000000a01000039000300000001001d000000000101041a000700000001001d0000000601000039000000000601041a0000000b01000039000200000001001d000000000701041a0000000c01000039000100000001001d000000000501041a000000400300043d0000080c0100004100000000001304350000000404300039000000000100041400000000002404350000004402300039000400000005001d000000000052043500000024023000390000000000720435000007b502600197000000040420008c000600000007001d000017430000613d000000640400003900000020060000390000000005030019000500000003001d1ebd02a00000040f00000005030000290000000607000029000000000110004c000018090000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000007b60410009c000017f50000213d0000000104500190000017f50000c13d000000400010043f0000001f0220008c000017eb0000a13d0000000002030433000500000002001d000008400220009c000017fc0000813d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000903000029000000000231004b0000000607000029000017ee0000413d00000000033100490000000501000029000007c4021000410000000101300190000007c401000041000000000102c019000000020430008c000017860000413d00000000452200a9000000000420004c000017710000613d000008410450009c000017eb0000213d00000000642500d9000000000224004b000017eb0000c13d00000001043002700000084202500041000007c46220012a00000002033001900000000003040019000017670000613d00000000631200a9000008420550009c0000177d0000813d000008410130009c000017820000a13d000017eb0000013d000008410530009c000017eb0000213d00000000652300d9000000000115004b000017eb0000c13d0000084201300041000007c43110012a0000000003040019000017670000013d00000000327100a9000000000310004c0000178c0000613d00000000431200d9000000000373004b000017ee0000c13d000007c42620012a000000000276004b000017ee0000413d00000000057600490000000802000039000000000302041a00000000425300a9000000000430004c000017980000613d00000000433200d9000000000353004b000017ee0000c13d000007c43220012a00000004030000290000000003320019000900000003001d000000000223004b000000000200001900000001020040390000000102200190000017ee0000c13d000000070200002900000000232100a9000000000210004c000017a90000613d00000000211300d90000000702000029000000000121004b000017ee0000c13d000500000005001d000007c30100004100000000001004390000800b010000390000000402000039000700000006001d000600000003001d1ebd02ee0000040f0000000802000029000000000012041b0000000601000029000007c41210012a0000000301000029000800000002001d000000000021041b00000002010000290000000702000029000000000021041b00000001010000290000000902000029000000000021041b0000000501000039000000000101041a000900000001001d1ebd16e30000040f000008130200004100000000002004390000000902000029000007b502200197000900000002001d0000000400200443000700000001001d000080020100003900000024020000391ebd02ee0000040f000000000110004c000017eb0000613d000000400500043d0000084301000041000000000015043500000044025000390000000001000414000000070300002900000000003204350000002402500039000000080300002900000000003204350000000402500039000000050300002900000000003204350000000902000029000000040320008c000017e70000613d00000064040000390000000003050019000900000005001d000000090500002900000000060000191ebd02690000040f0000000905000029000000000110004c000018090000613d000007b60150009c000017f50000213d000000400050043f000000000001042d000000000100001900000000020000191ebd030a0000040f000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f00000044021000390000084403000041000000000032043500000024021000390000001c030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000018180000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000018100000413d000000000530004c000018270000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f000007b5011001970000000003000411000000000113004b000018320000c13d0000000001000416000000000121004b000018400000c13d0000000001020019000000000001042d000000400100043d00000044021000390000084503000041000000000032043500000024021000390000000f030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f000000400100043d00000044021000390000084603000041000000000032043500000024021000390000000e030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f0000000003020019000000000401001900000001010000390000000002000414000007b504400197000000040540008c0000186e0000613d000000000130004c000018670000613d000007b101000041000007b10520009c0000000001024019000000c001100210000007cc011001c7000080090200003900000000050000191ebd1eb30000040f000000000301034f000000010120018f000300000003035500000000020300190000006002200270000107b10020019d000007b1022001970000186f0000013d0000000001020019000000000204001900000000030000190000000004000019000000000500001900000000060000191ebd02690000040f0000000102000031000000000320004c0000189f0000613d000008330320009c000018a20000813d0000003f03200039000000200400008a000000000443016f000000400300043d0000000004430019000000000534004b00000000050000190000000105004039000007b60640009c000018a20000213d0000000105500190000018a20000c13d000000400040043f00000000002304350000002002300039000000030300036700000001050000310000001f0450018f0000000505500272000018900000613d000000000600001900000005076002100000000008720019000000000773034f000000000707043b00000000007804350000000106600039000000000756004b000018880000413d000000000640004c0000189f0000613d0000000505500210000000000353034f00000000025200190000000304400210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000000110004c000018a90000613d000000000001042d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000400100043d000000440210003900000847030000410000000000320435000000240210003900000018030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f000c0000000000020000000504000039000700000004001d000000000504041a000000400700043d0000006404700039000c00000003001d0000000000340435000008480300004100000000003704350000000003000410000007b50430019700000004037000390000000000430435000b00000002001d000007b5032001970000004404700039000a00000003001d0000000000340435000900000001001d000007b5031001970000002401700039000500000003001d00000000003104350000000001000414000007b502500197000000040320008c000018dc0000613d0000008404000039000000200600003900000000030700190000000005070019000800000007001d1ebd02690000040f0000000807000029000000000110004c000019c80000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001730019000000000331004b00000000030000190000000103004039000007b60410009c000019ba0000213d0000000103300190000019ba0000c13d000000400010043f0000001f0220008c000019b70000a13d0000000002070433000000000320004c000019e80000c13d0000000901000039000000000101041a000800000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000802000029000000000112004b000019ee0000c13d0000000b010000291ebd16ab0000040f000b00000001001d000000010300008a0000000c02000029000000000332004b0000000002016019000c00000002001d00000009010000291ebd18290000040f0000000c020000290000000b01000029000000000121004b000019b00000413d0000000b01000039000800000001001d000000000201041a0000000c01000029000600000002001d000000000112004b000019b00000413d0000000c010000290000000b020000290000000002120049000900000002001d0000000a0100002900000000001004350000001001000039000300000001001d000000200010043f0000004002000039000400000002001d00000000010000191ebd02d70000040f0000000902000029000000000021041b0000000a0100002900000000001004350000000301000029000000200010043f000000000100001900000004020000291ebd02d70000040f0000000a03000039000000000203041a0000000101100039000000000021041b0000000c0500002900000006010000290000000001510049000200000001001d0000000802000029000000000012041b0000000901000029000007c4121000d1000800000002001d0000001201000039000100000001001d000000000101041a000007b5041001970000000b01000029000000000151004b0000193f0000613d0000000901000029000000080200002900000000211200d9000007c40110009c000019b00000c13d000300000003001d000000000103041a000600000001001d000000000110004c000019c10000613d00000813010000410000000000100439000000040040044300008002010000390000002402000039000400000004001d1ebd02ee0000040f000000000110004c000019b70000613d000000400500043d0000084b0100004100000000001504350000000801000029000000060200002900000000122100d900000044035000390000000001000414000000000023043500000024025000390000000a0300002900000000003204350000000402500039000008200300004100000000003204350000000403000029000000040230008c0000000002030019000019690000613d00000064040000390000000003050019000600000005001d000000060500002900000000060000191ebd02690000040f0000000605000029000000000110004c000019c80000613d000007b60150009c000019ba0000213d000000400050043f0000000701000029000000000101041a000007b5041001970000000c010000290000000b02000029000000000112004b0000000303000029000019790000613d0000000901000029000000080200002900000000211200d9000007c40110009c000019b00000c13d000000000103041a000b00000001001d000000000110004c000019c10000613d00000813010000410000000000100439000000040040044300008002010000390000002402000039000700000004001d1ebd02ee0000040f000000000110004c000019b70000613d000000400500043d0000084c01000041000000000015043500000008010000290000000b0200002900000000122100d9000000a4035000390000000001000414000000000023043500000084025000390000000203000029000000000032043500000064025000390000000903000029000000000032043500000044025000390000000c03000029000000000032043500000024025000390000000a0300002900000000003204350000000402500039000000050300002900000000003204350000000703000029000000040230008c0000000002030019000019ab0000613d000000c4040000390000000003050019000b00000005001d0000000b0500002900000000060000191ebd02690000040f0000000b05000029000000000110004c000019c80000613d000007b60150009c000019ba0000213d000000400050043f0000000c01000029000000000001042d000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000000000100001900000000020000191ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000000101000029000000040010043f000000240200003900000000010000191ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000019d70000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000019cf0000413d000000000530004c000019e60000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f000008490300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f000000400100043d0000084a02000041000000000021043500000004020000391ebd030a0000040f000a0000000000020000000505000039000600000005001d000000000505041a000000400700043d0000008406700039000300000003001d00000000003604350000084d030000410000000000370435000900000002001d000007b5032001970000006402700039000700000003001d0000000000320435000800000001001d000007b5031001970000004401700039000500000003001d0000000000310435000007b503400197000a00000003001d000000240170003900000000003104350000000001000410000100000001001d000007b5021001970000000401700039000200000002001d00000000002104350000000001000414000007b502500197000000040320008c00001a1e0000613d000000a404000039000000200600003900000000030700190000000005070019000400000007001d1ebd02690000040f0000000407000029000000000110004c00001b320000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001730019000000000331004b00000000030000190000000103004039000007b60410009c00001b2b0000213d000000010330019000001b2b0000c13d000000400010043f0000001f0220008c00001b280000a13d0000000002070433000000000320004c00001b520000c13d0000000901000039000000000101041a000400000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f000000400300043d0000000402000029000000000112004b00001b580000c13d0000085001000041000000000013043500000000010004140000000a02000029000000040420008c00001a4c0000613d00000004040000390000002006000039000400000003001d00000004050000291ebd02a00000040f0000000403000029000000000110004c00001b320000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000007b60420009c00001b2b0000213d000000010450019000001b2b0000c13d000000400020043f000000200110008c00001b280000413d0000000001030433000400000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000402000029000000000112004b00001b5d0000c13d00000009010000290000000802000029000000000121013f000007b501100198000000030300002900001b620000613d000000000130004c00001b670000613d000000010100008a000000000113004b00001b6c0000613d000000080100002900000009020000291ebd18b70000040f00000000040100190000000601000029000000000201041a000000400300043d00000852010000410000000000130435000000240630003900000000010004140000000a0500002900000000005604350000000407300039000000020600002900000000006704350000004406300039000300000004001d0000000000460435000007b502200197000000040420008c00001a910000613d000000640400003900000040060000390000000005030019000400000003001d1ebd02a00000040f00000004030000290000000a05000029000000000110004c00001b320000613d0000000101000031000000400210008c000000400200003900000000020140190000001f02200039000000e00220018f0000000007320019000000000227004b00000000020000190000000102004039000007b60470009c00001b2b0000213d000000010220019000001b2b0000c13d000000400070043f000000400110008c00001b280000413d0000000001030433000000000110004c00001b710000c13d00000020013000390000000004010433000008550100004100000000001704350000000402700039000000000100041400000007030000290000000000320435000000040250008c000400000004001d00001abc0000613d00000024040000390000002006000039000000000205001900000000030700190000000005070019000200000007001d1ebd02a00000040f000000020700002900000004040000290000000a05000029000000000110004c00001b320000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600220018f0000000008720019000007b60280009c00001b2b0000213d000000400080043f000000200110008c00001b280000413d0000000001070433000000000141004b00001b820000413d0000000101000029000000000115004b00001ad30000c13d0000000001050019000000080200002900000009030000291ebd1b9d0000040f00001af90000013d00000856010000410000000000180435000000440280003900000000010004140000000000420435000000240280003900000007030000290000000000320435000000040280003900000005030000290000000000320435000000040250008c00001aea0000613d00000064040000390000002006000039000000000205001900000000030800190000000005080019000900000008001d1ebd02690000040f0000000908000029000000000110004c00001b320000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600110018f0000000001810019000007b60310009c00001b2b0000213d000000400010043f000000200220008c00001b280000413d0000000002080433000000000220004c00001b900000c13d0000000601000029000000000101041a00000813020000410000000000200439000007b501100197000900000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c0000000a03000029000000040400002900001b280000613d000000400500043d00000858010000410000000000150435000000840250003900000000010004140000000000420435000000640250003900000000003204350000004402500039000000030300002900000000003204350000002402500039000000070300002900000000003204350000000402500039000000050300002900000000003204350000000902000029000000040320008c00001b240000613d000000a4040000390000000003050019000a00000005001d0000000a0500002900000000060000191ebd02690000040f0000000a05000029000000000110004c00001b320000613d000007b60150009c00001b2b0000213d000000400050043f000000000001042d000000000100001900000000020000191ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001b410000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001b390000413d000000000530004c00001b500000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f0000084e0300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f0000084f010000410000000000130435000000040200003900000000010300191ebd030a0000040f000000400100043d0000085102000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000085c02000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000085b02000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000085a02000041000000000021043500000004020000391ebd030a0000040f000000640170003900000853020000410000000000210435000000440170003900000854020000410000000000210435000000240170003900000033020000390000000000210435000007bc010000410000000000170435000000040170003900000020020000390000000000210435000000840200003900000000010700191ebd030a0000040f000000440180003900000859020000410000000000210435000000240180003900000018020000390000000000210435000007bc010000410000000000180435000000040180003900000020020000390000000000210435000000640200003900000000010800191ebd030a0000040f000000440210003900000857030000410000000000320435000000240210003900000014030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f000d0000000000020000000505000039000600000005001d000000000605041a000000400700043d0000008405700039000900000004001d0000000000450435000007b501100197000000240570003900000000001504350000085d010000410000000000170435000007b5033001970000006401700039000d00000003001d0000000000310435000007b5022001970000004401700039000c00000002001d00000000002104350000000001000410000400000001001d000007b5021001970000000401700039000300000002001d00000000002104350000000001000414000007b502600197000000040320008c00001bc50000613d000000a404000039000000200600003900000000030700190000000005070019000b00000007001d1ebd02690000040f0000000b07000029000000000110004c00001d280000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001730019000000000331004b00000000030000190000000103004039000007b60410009c00001d1a0000213d000000010330019000001d1a0000c13d000000400010043f0000001f0220008c00001d170000a13d0000000002070433000000000320004c00001d480000c13d0000000d020000290000000c03000029000000000232004b00001d4e0000613d000008100210009c00001d1a0000213d0000002002100039000000400020043f0000082b02000041000000000021043500000009030000290000082b213000d1000000000230004c00001beb0000613d000000090200002900000000322100d90000082b0220009c00001d210000c13d000007c41210012a000a00000002001d1ebd16e30000040f0000000002010019000000400100043d000008100310009c00001d1a0000213d0000002003100039000000400030043f00000000002104350000000a020000291ebd1e780000040f0000000001010433000007c41310012a0000000c01000039000000000201041a000100000003001d0000000003320019000700000003001d000000000223004b00000000020000190000000102004039000000010220019000001d210000c13d0000000702000029000000000021041b0000000d01000039000000000201041a0000000a03000029000000000332004b00001d210000413d0000000a030000290000000002320049000000000021041b0000000d0100002900000000001004350000000e01000039000b00000001001d000000200010043f0000004002000039000800000002001d00000000010000191ebd02d70000040f0000000d0200002900000000002004350000000b02000029000000200020043f000500000001001d000000000100001900000008020000291ebd02d70000040f000000000101041a0000000902000029000000000221004b00001d210000413d00000009020000290000000a030000290000000003320049000800000003001d00000000012100490000000502000029000000000012041b0000000c0100002900000000001004350000000b01000029000000200010043f0000004002000039000500000002001d00000000010000191ebd02d70000040f0000000c0200002900000000002004350000000b02000029000000200020043f000200000001001d000000000100001900000005020000291ebd02d70000040f000000000201041a00000008010000290000000001120019000000000221004b00000000020000190000000102004039000000010220019000001d210000c13d0000000b020000290000000202000029000000000012041b0000001201000039000200000001001d000000000101041a00000813020000410000000000200439000007b501100197000500000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00001d170000613d000000400500043d00000814010000410000000000150435000000440250003900000000010004140000000903000029000000000032043500000024025000390000000d0300002900000000003204350000000402500039000008150300004100000000003204350000000502000029000000040320008c00001c6a0000613d00000064040000390000000003050019000900000005001d000000090500002900000000060000191ebd02690000040f0000000905000029000000000110004c00001d280000613d000007b60150009c00001d1a0000213d000000400050043f0000000201000029000000000101041a00000813020000410000000000200439000007b501100197000900000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00001d170000613d000000400500043d0000081f010000410000000000150435000000440250003900000000010004140000000803000029000000000032043500000024025000390000000c0300002900000000003204350000000402500039000008150300004100000000003204350000000902000029000000040320008c00001c920000613d00000064040000390000000003050019000900000005001d000000090500002900000000060000191ebd02690000040f0000000905000029000000000110004c00001d280000613d000007b60150009c00001d1a0000213d000000400050043f00000008010000290000000000150435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10350009c00000000010540190000004001100210000000c002200210000000000112019f00000816011001c70000800d02000039000000030300003900000817040000410000000d050000290000000c060000291ebd1eb30000040f000000010120019000001d170000613d0000000601000029000000000101041a000900000001001d0000000d0100002900000000001004350000000b01000029000000200010043f0000004002000039000800000002001d00000000010000191ebd02d70000040f000000000101041a000600000001001d0000000c0100002900000000001004350000000b01000029000000200010043f000000000100001900000008020000291ebd02d70000040f000000000101041a000800000001001d000008130100004100000000001004390000000901000029000007b501100197000b00000001001d0000000400100443000080020100003900000024020000391ebd02ee0000040f000000000110004c00001d170000613d000000400500043d00000818010000410000000000150435000000640250003900000000010004140000000803000029000000000032043500000044025000390000000603000029000000000032043500000024025000390000000c03000029000000000032043500000004025000390000000d0300002900000000003204350000000b02000029000000040320008c00001ce60000613d00000084040000390000000003050019000c00000005001d0000000c0500002900000000060000191ebd02690000040f0000000c05000029000000000110004c00001d280000613d000007b60150009c00001d1a0000213d000000400050043f0000000a010000290000000000150435000007b1010000410000000002000414000007b10320009c0000000002018019000007b10350009c00000000010540190000004001100210000000c002200210000000000112019f00000816011001c70000800d02000039000000030300003900000817040000410000000d0500002900000004060000291ebd1eb30000040f000000010120019000001d170000613d000000400100043d00000040021000390000000703000029000000000032043500000020021000390000000103000029000000000032043500000003020000290000000000210435000007b1020000410000000003000414000007b10430009c0000000003028019000007b10410009c00000000010280190000004001100210000000c002300210000000000112019f00000805011001c70000800d02000039000000010300003900000806040000411ebd1eb30000040f000000010120019000001d170000613d000000000001042d000000000100001900000000020000191ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001d370000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001d2f0000413d000000000530004c00001d460000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f0000085e0300004100000000003104350000000403100039000000000023043500000024020000391ebd030a0000040f0000085f02000041000000000021043500000004020000391ebd030a0000040f000000000110004c00001d550000613d000000000001042d000000400100043d00000044021000390000083403000041000000000032043500000024021000390000001c030000390000000000320435000007bc02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391ebd030a0000040f00040000000000020000000302000039000000000202041a0000000802200270000007b5022001970000000003000411000000000223004b00001db90000c13d0000000502000039000300000002001d000000000202041a000000400300043d000007bf040000410000000000430435000007b502200197000200000002001d0000000002000414000007b501100197000400000001001d000000040110008c00001d820000613d0000000404000039000000200600003900000000010200190000000402000029000100000003001d00000001050000291ebd02a00000040f0000000103000029000000000110004c00001dc50000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000007b60420009c00001dbe0000213d000000010450019000001dbe0000c13d000000400020043f0000001f0110008c00001db60000a13d0000000001030433000000000210004c0000000002000019000000010200c039000000000221004b00001db60000c13d1ebd1d520000040f0000000302000029000000000102041a000007c0011001970000000403000029000000000131019f000000000012041b000000400100043d0000002002100039000000000032043500000002020000290000000000210435000007b1020000410000000003000414000007b10430009c0000000003028019000007b10410009c00000000010280190000004001100210000000c002300210000000000112019f000007c1011001c70000800d020000390000000103000039000007c2040000411ebd1eb30000040f000000010120019000001db60000613d000000000001042d000000000100001900000000020000191ebd030a0000040f000000400100043d0000086002000041000000000021043500000004020000391ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001dd40000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001dcc0000413d000000000530004c00001de30000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f0004000000000002000400000001001d0000000301000039000000000101041a0000000801100270000007b5011001970000000002000411000000000112004b00001e470000c13d0000000901000039000000000101041a000300000001001d000007c30100004100000000001004390000800b0100003900000004020000391ebd02ee0000040f0000000302000029000000000112004b00001e4c0000c13d0000000601000039000300000001001d000000000101041a000000400300043d000007c5020000410000000000230435000007b501100197000200000001001d00000000010004140000000402000029000007b502200197000400000002001d000000040220008c00001e100000613d000000040400003900000020060000390000000402000029000100000003001d00000001050000291ebd02a00000040f0000000103000029000000000110004c00001e580000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000007b60420009c00001e510000213d000000010450019000001e510000c13d000000400020043f0000001f0110008c00001e440000a13d0000000001030433000000000210004c0000000002000019000000010200c039000000000221004b00001e440000c13d1ebd1d520000040f0000000302000029000000000102041a000007c0011001970000000403000029000000000131019f000000000012041b000000400100043d0000002002100039000000000032043500000002020000290000000000210435000007b1020000410000000003000414000007b10430009c0000000003028019000007b10410009c00000000010280190000004001100210000000c002300210000000000112019f000007c1011001c70000800d020000390000000103000039000007c6040000411ebd1eb30000040f000000010120019000001e440000613d000000000001042d000000000100001900000000020000191ebd030a0000040f000000400100043d0000086102000041000000000021043500000004020000391ebd030a0000040f000000400100043d0000086202000041000000000021043500000004020000391ebd030a0000040f000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001e670000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001e5f0000413d000000000530004c00001e760000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311ebd030a0000040f000000400300043d000008280430009c00001e8c0000813d0000002004300039000000400040043f0000000000030435000000000101043300000000432100a9000000000410004c00001e850000613d00000000411300d9000000000121004b00001e930000c13d000000400100043d000008100210009c00001e8c0000213d0000002002100039000000400020043f0000000000310435000000000001042d000007c90100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c4431000d1000000000410004c00001ea00000613d00000000411300d9000007c40110009c00001eac0000c13d0000000001020433000000000210004c00001ea50000613d00000000211300d9000000000001042d000007c90100004100000000001004350000001201000039000000040010043f000000240200003900000000010000191ebd030a0000040f000007c90100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191ebd030a0000040f00001eb6002104210000000102000039000000000001042d000000000200001900001eb50000013d00001ebb002104230000000102000039000000000001042d000000000200001900001eba0000013d00001ebd0000043200001ebe0001042e00001ebf00010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff000000000000007f8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000ff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000010000000000000000000000000000000000000000726b6574000000000000000000000000000000000000000000000000000000006f6e6c792061646d696e206d617920696e697469616c697a6520746865206d6108c379a0000000000000000000000000000000000000000000000000000000006e636500000000000000000000000000000000000000000000000000000000006d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f007e3dd200000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000400000000000000000000000007ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320000000000000000000000000000000000000000000000000de0b6b3a76400002191f92a00000000000000000000000000000000000000000000000000000000edffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926ffffffffffffffffffffff00000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000006561746572207468616e207a65726f2e00000000000000000000000000000000696e697469616c2065786368616e67652072617465206d757374206265206772020000000000000000000000000000000000000000000000000000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000095ea7b3000000000000000000000000000000000000000000000000000000000cf4ceb4000000000000000000000000000000000000000000000000000000000d8ef28b000000000000000000000000000000000000000000000000000000001249c58b00000000000000000000000000000000000000000000000000000000173b99040000000000000000000000000000000000000000000000000000000017bfdfbc0000000000000000000000000000000000000000000000000000000018160ddd00000000000000000000000000000000000000000000000000000000182df0f5000000000000000000000000000000000000000000000000000000002138ec400000000000000000000000000000000000000000000000000000000023b872dd000000000000000000000000000000000000000000000000000000002678224700000000000000000000000000000000000000000000000000000000313ce567000000000000000000000000000000000000000000000000000000003af9e669000000000000000000000000000000000000000000000000000000003b1d21a2000000000000000000000000000000000000000000000000000000004576b5db0000000000000000000000000000000000000000000000000000000047bd3718000000000000000000000000000000000000000000000000000000004e4d9fea00000000000000000000000000000000000000000000000000000000558e889d000000000000000000000000000000000000000000000000000000005fe3b56700000000000000000000000000000000000000000000000000000000601a0bf1000000000000000000000000000000000000000000000000000000006752e7020000000000000000000000000000000000000000000000000000000069ab3250000000000000000000000000000000000000000000000000000000006c540baf0000000000000000000000000000000000000000000000000000000070a082310000000000000000000000000000000000000000000000000000000073acee9800000000000000000000000000000000000000000000000000000000852a12e3000000000000000000000000000000000000000000000000000000008f840ddd0000000000000000000000000000000000000000000000000000000095d89b410000000000000000000000000000000000000000000000000000000095dd919300000000000000000000000000000000000000000000000000000000a2d57df100000000000000000000000000000000000000000000000000000000a6afed9500000000000000000000000000000000000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000aa5af0fd00000000000000000000000000000000000000000000000000000000aae40a2a00000000000000000000000000000000000000000000000000000000ae9d70b000000000000000000000000000000000000000000000000000000000b2a02ff100000000000000000000000000000000000000000000000000000000b71d1a0c00000000000000000000000000000000000000000000000000000000bc30a61800000000000000000000000000000000000000000000000000000000bd6d894d00000000000000000000000000000000000000000000000000000000c37f68e200000000000000000000000000000000000000000000000000000000c5ebeaec00000000000000000000000000000000000000000000000000000000d69205c000000000000000000000000000000000000000000000000000000000db006a7500000000000000000000000000000000000000000000000000000000dd62ed3e00000000000000000000000000000000000000000000000000000000e597461900000000000000000000000000000000000000000000000000000000e9c714f200000000000000000000000000000000000000000000000000000000f2b3abbd00000000000000000000000000000000000000000000000000000000f3fdb15a00000000000000000000000000000000000000000000000000000000f851a44000000000000000000000000000000000000000000000000000000000f8f9da2800000000000000000000000000000000000000000000000000000000fca7820b00000000000000000000000000000000000000000000000000000000fcb6414700000000000000000000000000000000000000000000000000000000fe9c44ae38acf799000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000000000000000000000a91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5240b6af600000000000000000000000000000000000000000000000000000000fbf94d6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640001aaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460e2e441e60000000000000000000000000000000000000000000000000000000015f2405300000000000000000000000000000000000000000000000000000000f9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dcca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a96e893ca400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdfeabe7d9100000000000000000000000000000000000000000000000000000000480f4247000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83009c111600000000000000000000000000000000000000000000000000000000535550504c5900000000000000000000000000000000000000000000000000000200000000000000000000000000000000000020000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef085b7f0800000000000000000000000000000000000000000000000000000000ac6a406900000000000000000000000000000000000000000000000000000000e5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92951dff98900000000000000000000000000000000000000000000000000000000da3d454c00000000000000000000000000000000000000000000000000000000918db40f000000000000000000000000000000000000000000000000000000003a36318400000000000000000000000000000000000000000000000000000000dd56b3f200000000000000000000000000000000000000000000000000000000424f52524f570000000000000000000000000000000000000000000000000000f709dfcd0000000000000000000000000000000000000000000000000000000048c25881000000000000000000000000000000000000000000000000000000005cb56c2b00000000000000000000000000000000000000000000000000000000b816881600000000000000000000000000000000000000000000000000000000a6afed95000000000000000000000000000000000000000000000000000000007dd4936e00000000000000000000000000000000000000000000000000000000405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace000000000000000000000000000000000000000000000000ffffffffffffffe097b5cfcd0000000000000000000000000000000000000000000000000000000091240a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006379da05b60000dff50cb0000000000000000000000000000000000000000000000000000000003bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177ef1a5300a000000000000000000000000000000000000000000000000000000003345e99900000000000000000000000000000000000000000000000000000000f7e5e6d0000000000000000000000000000000000000000000000000000000008c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf600000000000000000000000000000000000000000000000100000000000000006d61726b6572206d6574686f642072657475726e65642066616c7365000000004ef4c3e10000000000000000000000000000000000000000000000000000000049abd4fd0000000000000000000000000000000000000000000000000000000038d88597000000000000000000000000000000000000000000000000000000004c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f6a6c276c0000000000000000000000000000000000000000000000000000000072652d656e746572656400000000000000000000000000000000000000000000bdcdc25800000000000000000000000000000000000000000000000000000000113a84ee000000000000000000000000000000000000000000000000000000008cd22d1900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf9cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f390000000000000000000000000000000000000000000000000000048c27395001fffffffffffffffffffffffffffffffffffffffffffffffff90fa4a62c4dffff00000000000000000000000000000000000000000000000006f05b59d3b200005736de3c00000000000000000000000000000000000000000000000000000000626f72726f772072617465206973206162737572646c7920686967680000000073656e646572206d69736d61746368000000000000000000000000000000000076616c7565206d69736d617463680000000000000000000000000000000000004661696c656420746f207472616e73666572206574686572000000000000000024008a62000000000000000000000000000000000000000000000000000000008c81362d00000000000000000000000000000000000000000000000000000000c9021e2f0000000000000000000000000000000000000000000000000000000080ac7a8f0000000000000000000000000000000000000000000000000000000028ea6143000000000000000000000000000000000000000000000000000000005fc7e71e000000000000000000000000000000000000000000000000000000001429a2f20000000000000000000000000000000000000000000000000000000080965b1b000000000000000000000000000000000000000000000000000000006c540baf0000000000000000000000000000000000000000000000000000000082379c6800000000000000000000000000000000000000000000000000000000c488847b00000000000000000000000000000000000000000000000000000000414d4f554e545f5345495a455f4641494c4544000000000000000000000000004c49515549444154455f434f4d5054524f4c4c45525f43414c43554c4154455f70a0823100000000000000000000000000000000000000000000000000000000b2a02ff100000000000000000000000000000000000000000000000000000000746f6b656e207365697a757265206661696c6564000000000000000000000000f6509350000000000000000000000000000000000000000000000000000000004c49515549444154455f5345495a455f544f4f5f4d5543480000000000000000b3058b7600000000000000000000000000000000000000000000000000000000d29da7ef000000000000000000000000000000000000000000000000000000006f46988400000000000000000000000000000000000000000000000000000000d02f735100000000000000000000000000000000000000000000000000000000c7c01c66000000000000000000000000000000000000000000000000000000007528c4ce00000000000000000000000000000000000000000000000000000000d219dc1f00000000000000000000000000000000000000000000000000000000407fded50000000000000000000000000000000000000000000000000000000017c54b9600000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0x00000000000000000000000023848c28af1c3aa7b999fa57e6b6e8599c17f3f2000000000000000000000000727d77d4ef5e5c75f4e0c4716d7a7a55c1467e5c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000001200000000000000000000000099999a3c4cb8427c44294ad36895b6a3a047060dff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace000000000000000000000000000000000000000000000000000000000000001352656163746f72467573696f6e2045746865720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057266455448000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : comptroller_ (address): 0x23848c28Af1C3AA7B999fA57e6b6E8599C17F3f2
Arg [1] : interestRateModel_ (address): 0x727d77d4Ef5E5C75f4E0C4716D7A7a55c1467e5c
Arg [2] : initialExchangeRateMantissa_ (uint256): 1000000000000000000
Arg [3] : name_ (string): ReactorFusion Ether
Arg [4] : symbol_ (string): rfETH
Arg [5] : decimals_ (uint8): 18
Arg [6] : admin_ (address): 0x99999A3C4cB8427c44294Ad36895b6a3A047060d
Arg [7] : pythId (bytes32): 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace
-----Encoded View---------------
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.