ERC-20
Overview
Max Total Supply
247,878.09187 ERC20 ***
Holders
70,965
Total Transfers
-
Market
Price
$0.00 @ 0.000000 ETH
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 6 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:
CErc20Immutable
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 "./CErc20.sol"; /** * @title Compound's CErc20Immutable Contract * @notice CTokens which wrap an EIP-20 underlying and are immutable * @author Compound */ contract CErc20Immutable is CErc20 { /** * @notice Construct a 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 * @param admin_ Address of the administrator of this token */ constructor( address underlying_, 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 the market initialize( underlying_, comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, pythId_ ); // Set the proper admin now that initialization is done admin = admin_; } }
// 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":"address","name":"underlying_","type":"address"},{"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":[{"internalType":"uint256","name":"addAmount","type":"uint256"}],"name":"_addReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","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":[{"internalType":"address","name":"underlying_","type":"address"},{"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":"pythId","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":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"contract CTokenInterface","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","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":[{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowBehalf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","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":[{"internalType":"contract EIP20NonStandardInterface","name":"token","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","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":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"dist_","type":"address"}],"name":"updateDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
9c4d535b00000000000000000000000000000000000000000000000000000000000000000100090557d1a37e5ea7476309e6f48901d8869c253d16c7c41519c16a81a40a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000003355df6d4c9c3035724fd0e3914de96a5a83aaf400000000000000000000000023848c28af1c3aa7b999fa57e6b6e8599c17f3f2000000000000000000000000035ed15ad908726b99bdf02001fb9715f5b99f060000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000600000000000000000000000099999a3c4cb8427c44294ad36895b6a3a047060deaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a000000000000000000000000000000000000000000000000000000000000001252656163746f72467573696f6e2055534443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067266555344430000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x0004000000000002000f000000000002000000000301001900000060033002700000084b04300197000300000041035500020000000103550000084b0030019d000100000000001f00000001012001900000000c0000c13d212503450000040f0000008001000039000000400010043f0000000001000416000000000110004c0000028a0000c13d00000000010000310000009f02100039000000200800008a000000000282016f0000084c032000410000084d0330009c0000001f0000213d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000400020043f0000001f0210018f000000020300036700000005041002720000002d0000613d00000000050000190000000506500210000000000763034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000250000413d000000000520004c0000003c0000613d0000000504400210000000000343034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f00000000002404350000084e02000041000001200310008c000000000300001900000000030240190000084e04100197000000000540004c000000000200a0190000084e0440009c000000000203c019000000000220004c0000028a0000c13d000000800400043d0000084f0240009c0000028a0000213d000000a00200043d0000084f062001970000084f0220009c0000028a0000213d000000c00200043d0000084f052001970000084f0220009c0000028a0000213d000000e00200043d000f00000002001d000001000700043d000008500370009c0000028a0000213d00000080021000390000008001700039000e00000002001d000900000004001d000a00000008001d000c00000005001d000d00000006001d2125133c0000040f000b00000001001d000001200100043d000008500210009c0000028a0000213d00000080011000390000000e020000292125133c0000040f0000000007010019000001400600043d000000ff0160008c0000028a0000213d000001600400043d0000084f0140009c0000028a0000213d0000000305000039000000000105041a0000085101100197000000000200041100000008032002100000085203300197000000000113019f000001800300043d000000000015041b000008530120009c0000009d0000813d0000000902000039000000000102041a000000000110004c000000ae0000c13d0000000a01000039000e00000001001d000000000101041a000000000110004c000000ae0000c13d000800000002001d000700000007001d000400000003001d000500000006001d000600000005001d000300000004001d00000007010000390000000f02000029000000000021041b000000000120004c000000bf0000c13d000000400100043d0000006402100039000008650300004100000000003204350000004402100039000008660300004100000000003204350000002402100039000000300300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000084020000392125033c0000040f000000400100043d0000006402100039000008540300004100000000003204350000004402100039000008550300004100000000003204350000002402100039000000240300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000084020000392125033c0000040f000000400100043d0000006402100039000008570300004100000000003204350000004402100039000008580300004100000000003204350000002402100039000000230300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000084020000392125033c0000040f0000000501000039000100000001001d000000000101041a000200000001001d000000400200043d0000085901000041000f00000002001d000000000012043500000000010004140000000d02000029000000040220008c000000f30000613d000000040400003900000020060000390000000d020000290000000f030000290000000005030019212502d40000040f000000000110004c000000f30000c13d0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000000e20000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000000da0000413d000000000530004c000000f10000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f0000000f020000290000000002230019000000000332004b00000000030000190000000103004039000008500420009c000000180000213d0000000103300190000000180000c13d000000400020043f000000200110008c0000000d030000290000028a0000413d0000000f010000290000000001010433000000000210004c0000000002000019000000010200c039000000000221004b0000028a0000c13d212513780000040f00000002030000290000085a013001970000000d04000029000000000141019f0000000102000029000000000012041b000000400100043d000000200210003900000000004204350000084f0230019700000000002104350000084b0200004100000000030004140000084b0430009c00000000030280190000084b0410009c00000000010280190000004001100210000000c002300210000000000112019f0000085b011001c70000800d0200003900000001030000390000085c040000412125211b0000040f0000000c0300002900000001012001900000028a0000613d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000802000029000000000012041b0000085e010000410000000e02000029000000000012041b0000000601000039000d00000001001d000000000101041a000e00000001001d0000085f01000041000000400200043d000f00000002001d000000000012043500000000010004140000000c02000029000000040220008c000001480000613d000000040400003900000020060000390000000c020000290000000f030000290000000005030019212502d40000040f000000000110004c000000d30000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f0000000f020000290000000002230019000000000332004b00000000030000190000000103004039000008500420009c000000180000213d0000000103300190000000180000c13d000000400020043f000000200110008c0000000c030000290000028a0000413d0000000f010000290000000001010433000000000210004c0000000002000019000000010200c039000000000221004b0000028a0000c13d212513780000040f0000000e030000290000085a013001970000000c04000029000000000141019f0000000d02000029000000000012041b000000400100043d000000200210003900000000004204350000084f0230019700000000002104350000084b0200004100000000030004140000084b0430009c00000000030280190000084b0410009c00000000010280190000004001100210000000c002300210000000000112019f0000085b011001c70000800d0200003900000001030000390000086004000041000f00000003001d2125211b0000040f00000001012001900000028a0000613d0000000b010000290000000001010433000e00000001001d000008500110009c000000180000213d0000000f01000029000000000101041a000000010210019000000001011002700000007f0310018f0000000001036019000d00000001001d0000001f0110008c00000000010000190000000101002039000000010110018f000000000112004b000001980000613d000008640100004100000000001004350000002201000039000000040010043f000000240200003900000000010000192125033c0000040f0000000d01000029000000200110008c000001b00000413d00000001010000390000000000100435000000200200003900000000010000192125030b0000040f0000000e030000290000001f023000390000000502200270000000200330008c000000000302001900000000030040190000000d020000290000001f02200039000000050220027000000000022100190000000001310019000000000321004b000001b00000813d000000000001041b0000000101100039000001ab0000013d0000000e020000290000001f0120008c0000000301200210000c00000001001d000001cb0000a13d0000000101000039000d00000001001d00000000001004350000002002000039000800000002001d00000000010000192125030b0000040f00000008060000290000000a020000290000000e03000029000000000223016f00000000030000190000000b05000029000000000423004b0000000004560019000001db0000813d0000000004040433000000000041041b000000200330003900000020066000390000000101100039000001c20000013d0000000e01000029000000000110004c0000000001000019000001d20000613d0000000b0100002900000020011000390000000001010433000000010200008a0000000c03000029000000000332022f000000000223013f000000000121016f0000000e020000290000000102200210000d00000002001d000001e80000013d0000000e03000029000000000232004b000001e60000813d0000000c02000029000000f80220018f000000010300008a000000000223022f000000000232013f0000000003040433000000000223016f000000000021041b0000000e0100002900000001011002100000000d02000029000000000121019f0000000f02000029000000000012041b00000007010000290000000001010433000e00000001001d000008500110009c000000180000213d0000000201000039000d00000001001d000000000101041a000000010210019000000001021002700000007f0320018f0000000002036019000c00000002001d0000001f0220008c00000000020000190000000102002039000000000121013f0000000101100190000001910000c13d0000000c01000029000000200110008c000002170000413d0000000d010000290000000000100435000000200200003900000000010000192125030b0000040f0000000e030000290000001f023000390000000502200270000000200330008c000000000302001900000000030040190000000c020000290000001f02200039000000050220027000000000022100190000000001310019000000000321004b000002170000813d000000000001041b0000000101100039000002120000013d0000000e010000290000001f0110008c0000022f0000a13d0000000d0100002900000000001004350000002002000039000c00000002001d00000000010000192125030b0000040f0000000c060000290000000a020000290000000e03000029000000000223016f00000000030000190000000705000029000000000423004b00000000045600190000023f0000813d0000000004040433000000000041041b000000200330003900000020066000390000000101100039000002260000013d0000000e01000029000000000110004c0000000001000019000002360000613d0000000701000029000000200110003900000000010104330000000e040000290000000302400210000000010300008a000000000223022f000000000232013f000000000121016f0000000102400210000f00000002001d0000024d0000013d0000000e03000029000000000232004b0000024b0000813d0000000e020000290000000302200210000000f80220018f000000010300008a000000000223022f000000000232013f0000000003040433000000000223016f000000000021041b0000000e0100002900000001011002100000000f02000029000000000121019f0000000d02000029000000000012041b0000000501000029000000ff0410018f0000000603000029000000000203041a000001000100008a000e00000002001d000000000212016f000d00000004001d000000000242019f000000000023041b00000011020000390000000403000029000000000032041b000000000200041a000000000112016f00000001011001bf000000000010041b00000009010000290000084f021001970000001301000039000000000301041a0000085a03300197000000000323019f000000000031041b0000086101000041000000400300043d000f00000003001d00000000001304350000000001000414000000040320008c000002770000613d000000040400003900000020060000390000000f030000290000000005030019212502d40000040f000000000110004c000000d30000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f0000000f020000290000000002230019000000000332004b00000000030000190000000103004039000008500420009c000000180000213d0000000103300190000000180000c13d000000400020043f000000200110008c00000003010000290000028d0000813d000000000100001900000000020000192125033c0000040f000000080110021000000852011001970000000d02000029000000000121019f0000000e020000290000086202200197000000000121019f0000000602000029000000000012041b000000200100003900000100001004430000012000000443000001000100003900000040020000390000086303000041212503320000040f0002000000000002000200000006001d000100000005001d0000084b050000410000084b0630009c000000000305801900000040033002100000084b0640009c00000000040580190000006004400210000000000334019f0000084b0410009c0000000001058019000000c001100210000000000113019f2125211b0000040f0000000109000029000000000301001900000060033002700000084b033001970000000205000029000000000453004b00000000050340190000001f0450018f0000000505500272000002c00000613d000000000600001900000005076002100000000008790019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002b80000413d000000010220018f000000000640004c000002d00000613d0000000505500210000000000651034f00000000055900190000000304400210000000000705043300000000074701cf000000000747022f000000000606043b0000010004400089000000000646022f00000000044601cf000000000474019f0000000000450435000100000003001f00030000000103550000000001020019000000000001042d0002000000000002000200000006001d000100000005001d0000084b050000410000084b0630009c000000000305801900000040033002100000084b0640009c00000000040580190000006004400210000000000334019f0000084b0410009c0000000001058019000000c001100210000000000113019f212521200000040f0000000109000029000000000301001900000060033002700000084b033001970000000205000029000000000453004b00000000050340190000001f0450018f0000000505500272000002f70000613d000000000600001900000005076002100000000008790019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002ef0000413d000000010220018f000000000640004c000003070000613d0000000505500210000000000651034f00000000055900190000000304400210000000000705043300000000074701cf000000000747022f000000000606043b0000010004400089000000000646022f00000000044601cf000000000474019f0000000000450435000100000003001f00030000000103550000000001020019000000000001042d0000084b030000410000084b0410009c000000000103801900000040011002100000006002200210000000000112019f00000000020004140000084b0420009c0000000002038019000000c002200210000000000121001900000867011000410000801002000039212521200000040f00000001022001900000031d0000613d000000000101043b000000000001042d000000000100001900000000020000192125033c0000040f00000000030100190000084b0100004100000000040004140000084b0540009c0000000001044019000000c0011002100000006002200210000000000112001900000868011000410000000002030019212521200000040f00000001022001900000032f0000613d000000000101043b000000000001042d000000000100001900000000020000192125033c0000040f0000084b040000410000084b0510009c0000000001048019000000400110021000000000013100190000084b0320009c000000000204801900000060022002100000000001210019000021260001042e0000084b030000410000084b0420009c00000000020380190000084b0410009c000000000103801900000040011002100000006002200210000000000112019f0000212700010430000b0000000000020000008001000039000000400010043f0000000001000031000000040110008c00000fd20000413d0000000201000367000000000101043b000000e001100270000008690210009c00000b180000613d0000086a0210009c0000000005000411000003d90000613d0000086b0210009c00000b480000613d0000086c0210009c00000b850000613d0000086d0210009c000004180000613d0000086e0210009c00000bca0000613d0000086f0210009c00000be20000613d000008700210009c000004430000613d000008710210009c0000045b0000613d000008720210009c0000000003000410000004730000613d000008730210009c000004a90000613d000008740210009c00000c0f0000613d000008750210009c000004e20000613d000008760210009c000005120000613d000008770210009c0000052b0000613d000008780210009c00000c300000613d000008790210009c000005440000613d0000087a0210009c0000055c0000613d0000087b0210009c00000c600000613d0000087c0210009c00000c7d0000613d0000087d0210009c000005aa0000613d0000087e0210009c000005f70000613d0000087f0210009c000006100000613d000008800210009c000006500000613d000008810210009c000006670000613d000008820210009c000006790000613d000008830210009c000006910000613d000008840210009c000006aa0000613d000008850210009c00000c950000613d000008860210009c00000cbc0000613d000008870210009c000006ce0000613d000008880210009c00000e3d0000613d000008890210009c000006e60000613d0000088a0210009c000007040000613d0000088b0210009c00000e6d0000613d0000088c0210009c000007470000613d0000088d0210009c000007600000613d0000088e0210009c000007770000613d0000088f0210009c00000fc10000613d000008900210009c000007a80000613d000008910210009c000007f20000613d000008920210009c000008120000613d000008930210009c000008480000613d000008940210009c0000086d0000613d000008950210009c000008850000613d000008960210009c000008b70000613d000008970210009c0000091f0000613d000008980210009c000009370000613d000008990210009c0000096d0000613d0000089a0210009c000009990000613d0000089b0210009c000009ee0000613d0000089c0210009c00000a0c0000613d0000089d0210009c00000a250000613d0000089e0210009c00000a7f0000613d0000089f0210009c00000a990000613d000008a00210009c00000adf0000613d000008a10110009c00000fd20000c13d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d000000400100043d0000000102000039000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000400310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000002010003670000000402100370000000000202043b000b00000002001d0000084f0220009c00000fd20000213d0000002401100370000000000101043b000900000001001d00000000005004350000000f01000039000000200010043f0000004002000039000800000002001d0000000001000019000a00000005001d2125030b0000040f0000000b020000290000000000200435000000200010043f000000000100001900000008020000292125030b0000040f0000000902000029000000000021041b000000400100043d00000000002104350000084b0200004100000000030004140000084b0430009c00000000030280190000084b0410009c00000000010280190000004001100210000000c002300210000000000112019f000008b3011001c70000800d020000390000000303000039000008d9040000410000000a050000290000000b060000292125211b0000040f000000010120019000000fd20000613d000003d30000013d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d000000000100041a000a00000001001d000000ff0110018f212515c10000040f000001000100008a000b00000001001d0000000a02000029000000000112016f000000000010041b212518c40000040f00000004010000390000000201100367000000000301043b0000000001000411000000000201001921251b200000040f000000000100041a0000000b02000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000d01000039000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d212518970000040f000000400300043d0000000000130435000000200200003900000000010300190000000003000019212503320000040f00000000060300190000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d0000084f0110009c00000fd20000213d0000000301000039000000000101041a00000008011002700000084f01100197000000000115004b000010160000c13d000000400700043d0000001301000039000000000101041a0000084f011001970000000b02000029000000000112004b000010820000c13d0000006401700039000008d60200004100000000002104350000004401700039000008d702000041000000000021043500000024017000390000003202000039000000000021043500000856010000410000000000170435000000040170003900000020020000390000000000210435000000840200003900000000010700192125033c0000040f0000000001000416000000000110004c00000fd20000c13d0000000003000031000000040130008a0000084e02000041000000200410008c000000000400001900000000040240190000084e01100197000000000510004c000000000200a0190000084e0110009c00000000010400190000000001026019000000000110004c00000fd20000c13d00000002020003670000000401200370000000000101043b000008500410009c00000fd20000213d00000023041000390000084e05000041000000000634004b000000000600001900000000060580190000084e073001970000084e04400197000000000874004b0000000005008019000000000474013f0000084e0440009c00000000040600190000000004056019000000000440004c00000fd20000c13d0000000404100039000000000242034f000000000202043b000008500420009c00000fd20000213d000000240110003900000005042002100000000004140019000000000334004b00000fd20000213d212517650000040f0000000002010019000000400100043d000b00000001001d212514280000040f0000000b03000029000000000231004900000000010300190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000400310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f000000000100041a000900000001001d000000ff0110018f212515c10000040f000001000100008a000a00000001001d0000000902000029000000000112016f000000000010041b212518c40000040f00000024010000390000000201100367000000000301043b00000000010004110000000b0200002921251b200000040f000000000100041a0000000a02000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000401000039000000000101041a0000084f02100197000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000301000039000000000101041a000000ff0210018f000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d2125180d0000040f000000400300043d0000000000130435000000200200003900000000010300190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d000a00000005001d000000000100041a000b00000001001d000000ff0110018f212515c10000040f000001000100008a0000000b02000029000000000112016f000000000010041b212518c40000040f0000000901000039000000000101041a000b00000001001d0000085d0100004100000000001004390000800b010000390000000402000039000900000002001d212503200000040f0000000b02000029000000000112004b00000fdc0000c13d00000009010000290000000201100367000000000201043b0000000a01000029212519dd0000040f0000000c03000039000000000403041a0000000002140019000000000442004b0000000004000019000000010400403900000001044001900000123a0000c13d000000000023041b000000400300043d00000040043000390000000000240435000000200230003900000000001204350000000a010000290000084f0110019700000000001304350000084b0100004100000000020004140000084b0420009c00000000020180190000084b0430009c00000000010340190000004001100210000000c002200210000000000112019f000008b7011001c70000800d020000390000000103000039000008d1040000412125211b0000040f000000010120019000000fd20000613d000010fb0000013d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d0000084f0110009c00000fd20000213d0000000b0100002900000000001004350000000e01000039000000200010043f0000004002000039000900000002001d00000000010000192125030b0000040f000000000101041a000a00000001001d0000001001000039000800000001001d000000200010043f000000000100001900000009020000292125030b0000040f0000000a040000290000000101100039000000000101041a000000000110004c0000000002000019000005f00000613d000000400200003900000000010000192125030b0000040f000000000101041a0000085e231000d1000000000210004c000005e10000613d00000000211300d90000085e0110009c0000123a0000c13d000900000003001d0000000b0100002900000000001004350000000801000029000000200010043f000000400200003900000000010000192125030b0000040f0000000101100039000000000101041a000000000210004c000009660000613d000000090200002900000000121200d90000000a04000029000000400100043d00000020031000390000000000230435000000000041043500000040020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000501000039000000000101041a0000084f02100197000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000900000001001d000000000100041a000b00000001001d000000ff0110018f000a00000005001d212515c10000040f000001000100008a0000000b02000029000000000112016f000000000010041b212518c40000040f0000000a020000290000000303000039000000000103041a00000008011002700000084f01100197000000000112004b0000063b0000613d0000001201000039000000000101041a0000084f01100197000000000112004b00000fff0000c13d000a00000003001d0000000901000039000000000101041a000b00000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000b02000029000000000112004b000010110000c13d2125180d0000040f0000000902000029000000000121004b000010790000813d000000400100043d000008cf02000041000000000021043500000004020000392125033c0000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d000000400100043d000008cb02000041000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000bc50000013d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000901000039000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000001301000039000000000101041a0000084f02100197000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f0000000b010000290000084f0110019700000000001004350000000e01000039000000200010043f000000400200003900000000010000192125030b0000040f000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000c01000039000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f0000000b010000292125185f0000040f000000400300043d0000000000130435000000200200003900000000010300190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d0000000002000031000000040120008a0000084e03000041000001000410008c000000000400001900000000040340190000084e01100197000000000510004c000000000300a0190000084e0110009c00000000010400190000000001036019000000000110004c00000fd20000c13d00000002010003670000000403100370000000000303043b000b00000003001d0000084f0330009c00000fd20000213d0000002403100370000000000303043b000a00000003001d0000084f0330009c00000fd20000213d0000004403100370000000000303043b000900000003001d0000084f0330009c00000fd20000213d0000008401100370000000000101043b000008500310009c00000fd20000213d0000000401100039212513d70000040f000800000001001d000000a4010000390000000201100367000000000101043b000008500210009c00000fd20000213d00000000020000310000000401100039212513d70000040f00000000060100190000000201000367000000c402100370000000000702043b000000ff0270008c00000fd20000213d000000e402100370000000000802043b0000006401100370000000000401043b0000000b010000290000000a02000029000000090300002900000008050000292125145c0000040f000000000100001900000000020000190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000001201000039000000000101041a0000084f02100197000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d212518c40000040f000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000400310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f000000000100041a000900000001001d000000ff0110018f212515c10000040f000001000100008a000a00000001001d0000000902000029000000000112016f000000000010041b00000024010000390000000201100367000000000401043b000000000100041100000000020100190000000b03000029212515d90000040f000000000100041a0000000a02000029000000000121016f00000001011001bf000000000010041b0000000102000039000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000601000039000000000101041a000b00000001001d2125180d0000040f00000000020100190000000b01000039000000000701041a0000000c01000039000000000401041a0000000801000039000000000501041a000000400300043d000008c20100004100000000001304350000006406300039000000000100041400000000005604350000004405300039000000000045043500000024043000390000000000740435000000040430003900000000002404350000000b020000290000084f02200197000000040420008c000007dc0000613d000000840400003900000020060000390000000005030019000b00000003001d212502d40000040f0000000b03000029000000000110004c000010940000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000008500410009c0000113a0000213d00000001045001900000113a0000c13d000000400010043f000000200220008c00000fd20000413d0000000002030433000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d0000000001000031212514400000040f000b00000001001d000a00000002001d000900000003001d000000000100041a000700000001001d000000ff0110018f212515c10000040f000001000100008a000800000001001d0000000702000029000000000112016f000000000010041b00000000010004110000000b020000290000000a03000029000000090400002921251e050000040f000000000100041a0000000802000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004020000390000000201200367000000000101043b0000084f0310009c00000fd20000213d0000000303000039000000000303041a00000008033002700000084f03300197000000000335004b00000fe30000c13d000000000302041a0000085a04300197000000000414019f000000000042041b000000400200043d000000200420003900000000001404350000084f0130019700000000001204350000084b0100004100000000030004140000084b0430009c00000000030180190000084b0420009c00000000010240190000004001100210000000c002300210000000000112019f0000085b011001c70000800d020000390000000103000039000008ab040000412125211b0000040f000000010120019000000bc50000c13d00000fd20000013d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b0000084f0210009c00000fd20000213d0000000302000039000000000202041a00000008022002700000084f02200197000000000225004b00000fe30000c13d0000001202000039000000000302041a0000085a03300197000000000113019f000000000012041b000000000100001900000000020000190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d212518850000040f000000400300043d0000000000130435000000200200003900000000010300190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f0000000b010000290000084f0110019700000000001004350000000e01000039000000200010043f000000400200003900000000010000192125030b0000040f000000000101041a000a00000001001d0000000b010000292125185f0000040f000b00000001001d212518970000040f000000400300043d00000020023000390000000a04000029000000000042043500000040023000390000000b040000290000000000420435000000600230003900000000001204350000000000030435000000800200003900000000010300190000000003000019212503320000040f000b00000003001d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000900000001001d000000000100041a000800000001001d000000ff0110018f000a00000005001d212515c10000040f000001000100008a000700000001001d0000000802000029000000000112016f000000000010041b212518c40000040f00000009050000290000000501000039000800000001001d000000000201041a000008ba01000041000000400300043d00000000001304350000000b010000290000084f06100197000000040430003900000000010004140000000000640435000000440430003900000000005404350000000a040000290000084f044001970000002406300039000b00000004001d00000000004604350000084f02200197000000040420008c000008f70000613d000000640400003900000020060000390000000005030019000600000003001d2125029d0000040f00000006030000290000000905000029000000000110004c000010940000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000060000190000000106004039000008500410009c0000113a0000213d00000001046001900000113a0000c13d000000400010043f000000200220008c00000fd20000413d0000000002030433000000000320004c000010cc0000c13d0000000901000039000000000101041a000600000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000602000029000000000112004b000011410000c13d2125180d0000040f0000000902000029000000000121004b0000115c0000813d000000400100043d000008c002000041000000000021043500000004020000392125033c0000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000001101000039000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f000b00000003001d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d000a00000005001d00000004010000390000000201100367000000000101043b000800000001001d000000000100041a000900000001001d000000ff0110018f212515c10000040f000001000100008a000700000001001d0000000902000029000000000112016f000000000010041b212518c40000040f212518970000040f000000400400043d000008ad0340009c0000113a0000213d0000002003400039000000400030043f00000000001404350000000802000029000000000320004c000010270000c13d000000000110004c00000000030000190000000a040000290000102d0000c13d000008640100004100000000001004350000001201000039000000040010043f000000240200003900000000010000192125033c0000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000400310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000201000367000b0000000103530000000401100370000000000101043b000a00000001001d212513d10000040f0000000b0100035f0000002401100370000000000101043b000b00000001001d212513d10000040f0000000a010000290000084f0110019700000000001004350000000f01000039000000200010043f000000400200003900000000010000192125030b0000040f0000000b02000029212515d20000040f000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000406000039000000000106041a0000084f01100197000000000115004b00000fe80000c13d000000000150004c00000fe80000613d00000008015002100000000302000039000000000302041a0000085104300197000000000114019f000000000012041b000000000106041a0000085a01100197000b00000006001d000000000016041b000000000102041a00000008011002700000084f01100197000000400200043d0000002004200039000000000014043500000008013002700000084f0110019700000000001204350000084b0100004100000000030004140000084b0430009c00000000030180190000084b0420009c00000000010240190000004001100210000000c002300210000000000112019f0000085b011001c70000800d020000390000000103000039000008aa04000041000a00000005001d2125211b0000040f0000000a04000029000000010120019000000fd20000613d0000000b01000029000000000101041a0000084f01100197000000400200043d0000002003200039000000000013043500000000004204350000084b0100004100000000030004140000084b0430009c00000000030180190000084b0420009c00000000010240190000004001100210000000c002300210000000000112019f0000085b011001c70000800d020000390000000103000039000008ab040000412125211b0000040f000000010120019000000bc50000c13d00000fd20000013d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f212518c40000040f0000000b010000292125204d0000040f000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000601000039000000000101041a0000084f02100197000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000600310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000002010003670000000402100370000000000202043b000b00000002001d0000084f0220009c00000fd20000213d0000004401100370000000000101043b000a00000001001d0000084f0110009c00000fd20000213d000000000100041a000900000001001d000000ff0110018f212515c10000040f000001000100008a000800000001001d0000000902000029000000000112016f000000000010041b212518c40000040f000008a801000041000000400300043d000000000013043500000000010004140000000a02000029000000040420008c00000a5a0000613d00000004040000390000002006000039000900000003001d00000009050000292125029d0000040f0000000903000029000000000110004c000010940000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000008500410009c0000113a0000213d00000001045001900000113a0000c13d000000400010043f000000200220008c00000fd20000413d0000000002030433000000000320004c000012160000c13d00000024010000390000000201100367000000000301043b00000000010004110000000b020000290000000a0400002921251c5b0000040f000000000100041a0000000802000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000301000039000000000101041a00000008011002700000084f02100197000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000601000039000000000101041a000b00000001001d2125180d0000040f00000000020100190000000b01000039000000000601041a0000000c01000039000000000401041a000000400300043d000008a701000041000000000013043500000044053000390000000001000414000000000045043500000024043000390000000000640435000000040430003900000000002404350000000b020000290000084f02200197000000040420008c00000ac90000613d000000640400003900000020060000390000000005030019000b00000003001d212502d40000040f0000000b03000029000000000110004c000010940000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000008500410009c0000113a0000213d00000001045001900000113a0000c13d000000400010043f000000200220008c00000fd20000413d0000000002030433000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000900000001001d000000000100041a000b00000001001d000000ff0110018f000a00000005001d212515c10000040f000001000100008a0000000b02000029000000000112016f000000000010041b212518c40000040f0000000301000039000000000101041a00000008011002700000084f011001970000000a02000029000000000112004b00000fed0000c13d0000000901000039000000000101041a000b00000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000b02000029000000000112004b000010740000c13d0000000904000029000008a40140009c000010b40000413d000000400100043d000008a602000041000000000021043500000004020000392125033c0000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000101000039000900000001001d000000000101041a000a00000001001d000000400200043d000b00000002001d212513890000040f0000000a030000290000000b070000290000000000170435000000010230019000000ff20000c13d000001000200008a000000000223016f00000020037000390000000000230435000000000110004c0000002002000039000000000200601900000020022000390000000001070019212513a70000040f000000400100043d000a00000001001d0000000b02000029212513bb0000040f0000000a03000029000000000231004900000000010300190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d0000000002000031000000040120008a0000084e03000041000000e00410008c000000000400001900000000040340190000084e01100197000000000510004c000000000300a0190000084e0110009c00000000010400190000000001036019000000000110004c00000fd20000c13d00000002010003670000000403100370000000000303043b000b00000003001d0000084f0330009c00000fd20000213d0000002403100370000000000303043b000a00000003001d0000084f0330009c00000fd20000213d0000006401100370000000000101043b000008500310009c00000fd20000213d0000000401100039212513d70000040f000900000001001d00000084010000390000000201100367000000000101043b000008500210009c00000fd20000213d00000000020000310000000401100039212513d70000040f00000000050100190000000201000367000000a402100370000000000602043b000000ff0260008c00000fd20000213d000000c402100370000000000702043b0000004401100370000000000301043b0000000b010000290000000a020000290000000904000029212514b70000040f000000000100001900000000020000190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000301000039000000000101041a00000008011002700000084f01100197000000000115004b00000ba10000613d0000001201000039000000000101041a0000084f01100197000000000115004b00000fff0000c13d000a00000005001d212518c40000040f0000000c01000039000b00000001001d000000000201041a000000000001041b0000001201000039000000000101041a0000084f0110019721251aad0000040f0000000b01000029000000000101041a000000400200043d000000200320003900000000001304350000000a010000290000084f011001970000000000120435000000400120003900000000000104350000084b0100004100000000030004140000084b0430009c00000000030180190000084b0420009c00000000010240190000004001100210000000c002300210000000000112019f000008b7011001c70000800d020000390000000103000039000008cd040000412125211b0000040f000000010120019000000fd20000613d000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000801000039000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f000000000100041a000900000001001d000000ff0110018f212515c10000040f000001000100008a000a00000001001d0000000902000029000000000112016f000000000010041b212518c40000040f0000000b010000292125185f0000040f000000000200041a0000000a03000029000000000232016f00000001022001bf000000000020041b000000400300043d0000000000130435000000200200003900000000010300190000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d0000000001000031212514400000040f000b00000001001d000a00000002001d000900000003001d000000000100041a000700000001001d000000ff0110018f212515c10000040f000001000100008a000800000001001d0000000702000029000000000112016f000000000010041b00000000010004110000000b020000290000000a030000290000000904000029212515d90000040f000000000100041a0000000802000029000000000121016f00000001011001bf000000000010041b0000000102000039000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000a00000001001d212513d10000040f212518850000040f000900000001001d000000400100043d000b00000001001d2125139b0000040f0000000b01000029000000090200002900000000002104350000000a010000290000084f0110019700000000001004350000000e01000039000000200010043f000000400200003900000000010000192125030b0000040f000000000201041a0000000b01000029212520e00000040f00000000010104330000085e1210012a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000b00000001001d212513d10000040f0000000b0100002921251fcb0000040f000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000b01000039000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d000000000100041a000a00000001001d000000ff0110018f212515c10000040f000001000100008a000b00000001001d0000000a02000029000000000112016f000000000010041b212518c40000040f000000000100041a0000000b02000029000000000121016f00000001011001bf0000000b02000039000000000202041a000000000010041b000000400100043d000000000021043500000020020000390000000003000019212503320000040f000b00000003001d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d000a00000005001d00000004010000390000000201100367000000000101043b000800000001001d000000000100041a000900000001001d000000ff0110018f212515c10000040f000001000100008a000700000001001d0000000902000029000000000112016f000000000010041b212518c40000040f212518970000040f000000400200043d000008ad0320009c0000113a0000213d0000002003200039000000400030043f00000000001204350000000801000029212521020000040f00000000040100190000000501000039000400000001001d000000000201041a000000400500043d000008ae01000041000000000015043500000044035000390000000001000414000600000004001d00000000004304350000000a030000290000084f043001970000002403500039000500000004001d00000000004304350000000b030000290000084f043001970000000403500039000300000004001d00000000004304350000084f02200197000000040320008c00000d070000613d000000640400003900000020060000390000000003050019000900000005001d00000009050000292125029d0000040f0000000905000029000000000110004c000010940000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001530019000000000331004b00000000030000190000000103004039000008500410009c0000113a0000213d00000001033001900000113a0000c13d000000400010043f000000200220008c00000fd20000413d0000000002050433000000000320004c000011460000c13d0000000901000039000000000101041a000900000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000902000029000000000112004b000011510000c13d2125180d0000040f0000000802000029000000000121004b0000106f0000413d0000000d01000039000000000201041a0000000603000029000000000332004b0000000a030000290000123a0000413d00000006030000290000000002320049000000000021041b000000050100002900000000001004350000000e01000039000900000001001d000000200010043f0000004002000039000200000002001d00000000010000192125030b0000040f000000050200002900000000002004350000000902000029000000200020043f000100000001001d000000000100001900000002020000292125030b0000040f000000000101041a0000000602000029000000000221004b0000123a0000413d000000060200002900000000012100490000000102000029000000000012041b0000000a01000029000000080200002921251aad0000040f0000001201000039000000000101041a000008b00200004100000000002004390000084f01100197000200000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b10100004100000000001404350000004402400039000000000100041400000006030000290000000000320435000000240240003900000005030000290000000000320435000100000004001d0000000402400039000008b20300004100000000003204350000000202000029000000040220008c00000d740000613d000000640400003900000002020000290000000103000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000101000029000008500110009c0000113a0000213d0000000104000029000000400040043f000000060100002900000000001404350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0340009c00000000010440190000004001100210000000c002200210000000000112019f000008b3011001c70000800d020000390000000303000039000008b4040000410000000a050000290000000b060000292125211b0000040f000000010120019000000fd20000613d0000000401000029000000000101041a000b00000001001d000000050100002900000000001004350000000901000029000000200010043f000000400200003900000000010000192125030b0000040f000000000101041a000a00000001001d000008b00100004100000000001004390000000b010000290000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b5010000410000000000140435000000440240003900000000010004140000000a030000290000000000320435000000240240003900000003030000290000000000320435000000040240003900000005030000290000000000320435000a00000004001d000000640240003900000000000204350000000b02000029000000040220008c00000dbf0000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a01000029000000400010043f0000000401000029000000000101041a000008b00200004100000000002004390000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b60100004100000000001404350000004402400039000000000100041400000006030000290000000000320435000000240240003900000008030000290000000000320435000a00000004001d0000000402400039000000050300002900000000003204350000000b02000029000000040220008c00000de90000613d00000064040000390000000b020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a04000029000000400040043f000000400140003900000006020000290000000000210435000000200140003900000008020000290000000000210435000000050100002900000000001404350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0340009c00000000010440190000004001100210000000c002200210000000000112019f000008b7011001c70000800d020000390000000103000039000008b8040000412125211b0000040f000000010120019000000fd20000613d0000000401000029000000000101041a000008b00200004100000000002004390000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b90100004100000000001404350000006402400039000000000100041400000006030000290000000000320435000000440240003900000008030000290000000000320435000000240240003900000005030000290000000000320435000a00000004001d0000000402400039000000030300002900000000003204350000000b02000029000000040220008c00000e2e0000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a01000029000000400010043f000000000100041a0000000702000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d0000000201000039000900000001001d000000000101041a000a00000001001d000000400200043d000b00000002001d212513890000040f0000000a030000290000000b0700002900000000001704350000000102300190000010040000c13d000001000200008a000000000223016f00000020037000390000000000230435000000000110004c0000002002000039000000000200601900000020022000390000000001070019212513a70000040f000000400100043d000a00000001001d0000000b02000029212513bb0000040f0000000a03000029000000000231004900000000010300190000000003000019212503320000040f000b00000003001d0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000200310008c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd20000c13d00000004010000390000000201100367000000000101043b000900000001001d000000000100041a000800000001001d000000ff0110018f000a00000005001d212515c10000040f000001000100008a000400000001001d0000000802000029000000000112016f000000000010041b212518c40000040f0000000501000039000600000001001d000000000201041a000008c301000041000000400500043d000000000015043500000044035000390000000001000414000000090400002900000000004304350000000a030000290000084f043001970000002403500039000700000004001d00000000004304350000000b030000290000084f043001970000000403500039000500000004001d00000000004304350000084f02200197000000040320008c00000eae0000613d000000640400003900000020060000390000000003050019000800000005001d00000008050000292125029d0000040f0000000805000029000000000110004c000010940000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001530019000000000331004b00000000030000190000000103004039000008500410009c0000113a0000213d00000001033001900000113a0000c13d000000400010043f000000200220008c00000fd20000413d0000000002050433000000000320004c000010d20000c13d0000000901000039000000000101041a000800000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000802000029000000000112004b0000114c0000c13d212518970000040f000000400300043d000008ad0230009c0000113a0000213d0000002002300039000000400020043f00000000001304350000000a010000290000000902000029000900000003001d212519dd0000040f000800000001001d0000000902000029212521020000040f0000000d04000039000000000304041a000900000001001d0000000002130019000000000332004b0000000003000019000000010300403900000001033001900000123a0000c13d000000000024041b000000070100002900000000001004350000000e01000039000300000001001d000000200010043f0000004002000039000200000002001d00000000010000192125030b0000040f000000070200002900000000002004350000000302000029000000200020043f000100000001001d000000000100001900000002020000292125030b0000040f000000000201041a00000009010000290000000001120019000000000221004b0000000002000019000000010200403900000001022001900000123a0000c13d0000000102000029000000000012041b0000001201000039000000000101041a000008b00200004100000000002004390000084f01100197000200000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008bd0100004100000000001404350000004402400039000000000100041400000009030000290000000000320435000000240240003900000007030000290000000000320435000100000004001d0000000402400039000008b20300004100000000003204350000000202000029000000040220008c00000f250000613d000000640400003900000002020000290000000103000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000101000029000008500110009c0000113a0000213d0000000104000029000000400040043f000000400140003900000009020000290000000000210435000000200140003900000008020000290000000000210435000000070100002900000000001404350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0340009c00000000010440190000004001100210000000c002200210000000000112019f000008b7011001c70000800d020000390000000103000039000008c6040000412125211b0000040f000000010120019000000fd20000613d0000000601000029000000000101041a000008b00200004100000000002004390000084f01100197000200000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008c70100004100000000001404350000004402400039000000000100041400000009030000290000000000320435000000240240003900000008030000290000000000320435000800000004001d0000000402400039000000070300002900000000003204350000000202000029000000040220008c00000f670000613d000000640400003900000002020000290000000803000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000801000029000008500110009c0000113a0000213d0000000804000029000000400040043f000000090100002900000000001404350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0340009c00000000010440190000004001100210000000c002200210000000000112019f000008b3011001c70000800d020000390000000303000039000008b4040000410000000b050000290000000a060000292125211b0000040f000000010120019000000fd20000613d0000000601000029000000000101041a000b00000001001d000000070100002900000000001004350000000301000029000000200010043f000000400200003900000000010000192125030b0000040f000000000101041a000a00000001001d000008b00100004100000000001004390000000b010000290000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b5010000410000000000140435000000640240003900000000010004140000000a030000290000000000320435000000240240003900000007030000290000000000320435000000040240003900000005030000290000000000320435000a00000004001d000000440240003900000000000204350000000b02000029000000040220008c00000fb20000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a01000029000000400010043f000000000100041a0000000402000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000001000416000000000110004c00000fd20000c13d000000040100008a00000000011000310000084e02000041000000000310004c000000000300001900000000030240190000084e01100197000000000410004c000000000200a0190000084e0110009c00000000010300190000000001026019000000000110004c00000fd50000613d000000000100001900000000020000192125033c0000040f0000000a01000039000000000201041a000000400100043d000000000021043500000020020000390000000003000019212503320000040f000000400100043d000008d00200004100000000002104350000000402100039000000000002043500000024020000392125033c0000040f000000400100043d000008c102000041000000000021043500000004020000392125033c0000040f000000400100043d000008ac02000041000000000021043500000004020000392125033c0000040f000000400100043d000008a202000041000000000021043500000004020000392125033c0000040f00000009020000290000000000200435000008da0300004100000020047000390000000002000019000000000512004b00000b3c0000813d0000000005240019000000000603041a00000000006504350000002002200039000000010330003900000ff70000013d000000400100043d000008d802000041000000000021043500000004020000392125033c0000040f00000009020000290000000000200435000008c80300004100000020047000390000000002000019000000000512004b00000e610000813d0000000005240019000000000603041a000000000065043500000020022000390000000103300039000010090000013d000000400100043d000008cc02000041000000000021043500000004020000392125033c0000040f000000400100043d0000006402100039000008d20300004100000000003204350000004402100039000008d303000041000000000032043500000024021000390000002f0300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000084020000392125033c0000040f0000000001040019212520e00000040f000000080200002900000000010104330000085e1310012a0000000a04000029000900000003001d0000000501000039000500000001001d000000000501041a000000400700043d000008ae0100004100000000001704350000004403700039000000000100041400000000002304350000084f024001970000002403700039000600000002001d00000000002304350000000b030000290000084f023001970000000403700039000400000002001d00000000002304350000084f02500197000000040320008c0000104c0000613d0000006404000039000000200600003900000000030700190000000005070019000300000007001d2125029d0000040f0000000307000029000000000110004c000010940000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001730019000000000331004b00000000030000190000000103004039000008500410009c0000113a0000213d00000001033001900000113a0000c13d000000400010043f000000200220008c00000fd20000413d0000000002070433000000000320004c000011560000c13d0000000901000039000000000101041a000300000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000302000029000000000112004b000011510000c13d2125180d0000040f0000000902000029000000000121004b0000121c0000813d000000400100043d000008ca02000041000000000021043500000004020000392125033c0000040f000000400100043d000008a302000041000000000021043500000004020000392125033c0000040f0000000c01000039000000000401041a000000000324004b000010d80000813d000000400100043d000008ce02000041000000000021043500000004020000392125033c0000040f000a00000005001d000008d40100004100000000001704350000084f04600197000000040370003900000000010004140000000000430435000000040320008c000011050000613d0000002404000039000000200600003900000000030700190000000005070019000900000007001d212502d40000040f0000000907000029000000000110004c000011050000c13d0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000010a30000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b0000109b0000413d000000000530004c000010b20000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f0000000801000039000000000201041a000000000041041b000000400100043d0000002003100039000000000043043500000000002104350000084b0200004100000000030004140000084b0430009c00000000030280190000084b0410009c00000000010280190000004001100210000000c002300210000000000112019f0000085b011001c70000800d020000390000000103000039000008a5040000412125211b0000040f0000000101200190000010fb0000c13d00000fd20000013d000008bb0300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f000008c40300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f0000000003240049000b00000003001d000000000031041b0000001201000039000000000101041a0000084f0110019721251aad0000040f0000000a01000029000000000101041a000000400200043d00000040032000390000000b04000029000000000043043500000020032000390000000904000029000000000043043500000008011002700000084f0110019700000000001204350000084b0100004100000000030004140000084b0430009c00000000030180190000084b0420009c00000000010240190000004001100210000000c002300210000000000112019f000008b7011001c70000800d020000390000000103000039000008cd040000412125211b0000040f000000010120019000000fd20000613d000001000100008a000000000200041a000000000112016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000000050700190000000002730019000000000332004b00000000030000190000000103004039000008500420009c0000113a0000213d00000001033001900000113a0000c13d000000400020043f000000200110008c00000fd20000413d0000000001050433000900000001001d000008b00100004100000000001004390000000b01000029000000040010044300008002010000390000002402000039212503200000040f0000000a03000029000000000110004c00000fd20000613d000000400400043d000008d50100004100000000001404350000002402400039000000000100041400000009050000290000000000520435000900000004001d000000040240003900000000003204350000000b02000029000000040320008c000011370000613d00000044040000390000000903000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000901000029000008500110009c000012410000a13d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000400100043d000008bc02000041000000000021043500000004020000392125033c0000040f000008af0300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f000000400100043d000008c502000041000000000021043500000004020000392125033c0000040f000000400100043d000008c902000041000000000021043500000004020000392125033c0000040f000008af0300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f0000000a010000292125185f0000040f00000009020000290000000002210019000600000002001d000000000112004b0000000001000019000000010100403900000001011001900000123a0000c13d0000000b01000039000400000001001d000000000101041a00000009020000290000000002210019000500000002001d000000000112004b0000000001000019000000010100403900000001011001900000123a0000c13d0000000b0100002900000000001004350000001001000039000300000001001d000000200010043f0000004002000039000200000002001d00000000010000192125030b0000040f0000000602000029000000000021041b0000000b0100002900000000001004350000000301000029000000200010043f000000000100001900000002020000292125030b0000040f0000000a02000039000300000002001d000000000202041a0000000101100039000000000021041b00000005010000290000000402000029000000000012041b0000000a01000029000000090200002921251aad0000040f00000009030000290000085e123000d1000a00000002001d0000001201000039000000000101041a0000084f01100197000400000001001d000000000130004c0000119c0000613d00000009010000290000000a0200002900000000211200d90000085e0110009c0000123a0000c13d0000000301000029000000000101041a000200000001001d000000000110004c000009660000613d000008b00100004100000000001004390000000401000029000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008bd0100004100000000001404350000000a01000029000000020200002900000000122100d900000044034000390000000001000414000000000023043500000024024000390000000b030000290000000000320435000a00000004001d0000000402400039000008be0300004100000000003204350000000402000029000000040220008c000011c50000613d000000640400003900000004020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a01000029000000400010043f00000006020000290000085e132000d1000a00000003001d0000000801000029000000000101041a0000084f01100197000800000001001d000000000120004c000011d80000613d00000006010000290000000a0200002900000000211200d90000085e0110009c0000123a0000c13d0000000301000029000000000101041a000400000001001d000000000110004c000009660000613d000008b00100004100000000001004390000000801000029000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008bf0100004100000000001404350000000a01000029000000040200002900000000122100d9000000840340003900000000010004140000000000230435000000640240003900000005030000290000000000320435000000440240003900000006030000290000000000320435000000240240003900000009030000290000000000320435000a00000004001d00000004024000390000000b0300002900000000003204350000000802000029000000040220008c000012070000613d000000a40400003900000008020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a01000029000000400010043f000000000100041a0000000702000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f000008a90300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f0000000d01000039000000000201041a0000000803000029000000000332004b0000000a030000290000123a0000413d00000008030000290000000002320049000000000021041b000000060100002900000000001004350000000e01000039000300000001001d000000200010043f0000004002000039000200000002001d00000000010000192125030b0000040f000000060200002900000000002004350000000302000029000000200020043f000100000001001d000000000100001900000002020000292125030b0000040f000000000101041a0000000802000029000000000221004b000012470000813d000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000901000029000000400010043f000000000100001900000000020000190000000003000019212503320000040f000000080200002900000000012100490000000102000029000000000012041b0000000a01000029000000090200002921251aad0000040f0000001201000039000000000101041a000008b00200004100000000002004390000084f01100197000200000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b10100004100000000001404350000004402400039000000000100041400000008030000290000000000320435000000240240003900000006030000290000000000320435000100000004001d0000000402400039000008b20300004100000000003204350000000202000029000000040220008c000012730000613d000000640400003900000002020000290000000103000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000101000029000008500110009c0000113a0000213d0000000104000029000000400040043f000000080100002900000000001404350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0340009c00000000010440190000004001100210000000c002200210000000000112019f000008b3011001c70000800d020000390000000303000039000008b4040000410000000a050000290000000b060000292125211b0000040f000000010120019000000fd20000613d0000000501000029000000000101041a000b00000001001d000000060100002900000000001004350000000301000029000000200010043f000000400200003900000000010000192125030b0000040f000000000101041a000a00000001001d000008b00100004100000000001004390000000b010000290000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b5010000410000000000140435000000440240003900000000010004140000000a030000290000000000320435000000240240003900000004030000290000000000320435000000040240003900000006030000290000000000320435000a00000004001d000000640240003900000000000204350000000b02000029000000040220008c000012be0000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a01000029000000400010043f0000000501000029000000000101041a000008b00200004100000000002004390000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b60100004100000000001404350000004402400039000000000100041400000008030000290000000000320435000000240240003900000009030000290000000000320435000a00000004001d0000000402400039000000060300002900000000003204350000000b02000029000000040220008c000012e80000613d00000064040000390000000b020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a04000029000000400040043f000000400140003900000008020000290000000000210435000000200140003900000009020000290000000000210435000000060100002900000000001404350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0340009c00000000010440190000004001100210000000c002200210000000000112019f000008b7011001c70000800d020000390000000103000039000008b8040000412125211b0000040f000000010120019000000fd20000613d0000000501000029000000000101041a000008b00200004100000000002004390000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000fd20000613d000000400400043d000008b90100004100000000001404350000006402400039000000000100041400000008030000290000000000320435000000440240003900000009030000290000000000320435000000240240003900000006030000290000000000320435000a00000004001d0000000402400039000000040300002900000000003204350000000b02000029000000040220008c0000132d0000613d00000084040000390000000b020000290000000a03000029000000000503001900000000060000192125029d0000040f000000000110004c000010940000613d0000000a01000029000008500110009c0000113a0000213d0000000a01000029000000400010043f000000000100041a0000000702000029000000000121016f00000001011001bf000000000010041b000000400100043d000000000001043500000020020000390000000003000019212503320000040f0000001f031000390000084e04000041000000000523004b000000000500001900000000050440190000084e062001970000084e03300197000000000763004b000000000400a019000000000363013f0000084e0330009c00000000030500190000000003046019000000000330004c000013750000613d0000000004010433000008db0340009c0000136e0000813d0000003f03400039000000200500008a000000000553016f000000400300043d0000000005530019000000000635004b00000000060000190000000106004039000008500750009c0000136e0000213d00000001066001900000136e0000c13d000000400050043f000000000043043500000000054100190000002005500039000000000225004b000013750000213d0000000002000019000000000542004b000013690000813d00000020022000390000000005320019000000000612001900000000060604330000000000650435000013610000013d0000000001340019000000200110003900000000000104350000000001030019000000000001042d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000000100001900000000020000192125033c0000040f000000000110004c0000137b0000613d000000000001042d000000400100043d0000004402100039000008dc03000041000000000032043500000024021000390000001c0300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000064020000392125033c0000040f000000010210019000000001011002700000007f0310018f00000000010360190000001f0310008c00000000030000190000000103002039000000010330018f000000000232004b000013940000c13d000000000001042d000008640100004100000000001004350000002201000039000000040010043f000000240200003900000000010000192125033c0000040f000008dd0210009c000013a00000813d0000002001100039000000400010043f000000000001042d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000001f02200039000000200300008a000000000232016f0000000001120019000000000221004b00000000020000190000000102004039000008500310009c000013b40000213d0000000102200190000013b40000c13d000000400010043f000000000001042d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000002003000039000000000031043500000000030204330000002004100039000000000034043500000040011000390000000004000019000000000534004b000013ca0000813d00000000054100190000002004400039000000000624001900000000060604330000000000650435000013c20000013d000000000231001900000000000204350000001f02300039000000200300008a000000000232016f0000000001210019000000000001042d000008530110009c000013d40000813d000000000001042d000000000100001900000000020000192125033c0000040f00000000030100190000001f013000390000084e04000041000000000521004b000000000500001900000000050440190000084e062001970000084e01100197000000000761004b000000000400a019000000000161013f0000084e0110009c00000000010500190000000001046019000000000110004c000014250000613d0000000201300367000000000401043b000008db0140009c0000141e0000813d0000003f01400039000000200500008a000000000551016f000000400100043d0000000005510019000000000615004b00000000060000190000000106004039000008500750009c0000141e0000213d00000001066001900000141e0000c13d000000400050043f000000000041043500000020033000390000000005430019000000000225004b000014250000213d0000001f0240018f0000000205300367000000200310003900000005064002720000140b0000613d000000000700001900000005087002100000000009830019000000000885034f000000000808043b00000000008904350000000107700039000000000867004b000014030000413d000000000720004c0000141a0000613d0000000506600210000000000565034f00000000036300190000000302200210000000000603043300000000062601cf000000000626022f000000000505043b0000010002200089000000000525022f00000000022501cf000000000262019f0000000000230435000000000214001900000020022000390000000000020435000000000001042d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000000100001900000000020000192125033c0000040f0000002003000039000000000031043500000020041000390000000003020433000000000034043500000000040000190000004001100039000000000534004b0000143f0000813d0000002002200039000000000502043300000000060100190000000007000019000000010870008c0000143d0000213d00000000080504330000000000860435000000010770003900000020055000390000002006600039000014350000013d00000001044000390000142e0000013d000000000001042d000000040110008a0000084e020000410000005f0310008c000000000300001900000000030220190000084e01100197000000000410004c00000000020080190000084e0110009c00000000010300190000000001026019000000000110004c000014590000613d00000002030003670000000401300370000000000101043b0000084f0210009c000014590000213d0000002402300370000000000202043b0000084f0420009c000014590000213d0000004403300370000000000303043b000000000001042d000000000100001900000000020000192125033c0000040f0001000000000002000100000001001d0000000001020019000000000203001900000000030400190000000004050019000000000506001900000000060700190000000007080019212514b70000040f00000001010000290000084f021001970000001301000039000000000301041a0000085a03300197000000000323019f000000000031041b0000086101000041000000400300043d00000000001304350000000001000414000000040420008c0000147b0000613d00000004040000390000002006000039000100000003001d0000000105000029212502d40000040f0000000103000029000000000110004c000014970000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000342004b00000000030000190000000103004039000008500420009c0000148d0000213d00000001033001900000148d0000c13d000000400020043f0000001f0110008c000014940000a13d000000000001042d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000000100001900000000020000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000014a60000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b0000149e0000413d000000000530004c000014b50000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f00080000000000020000000308000039000000000908041a00000008099002700000084f0a90019700000000090004110000000009a9004b0000159f0000c13d000000090a00003900000000090a041a000000000990004c000015870000c13d0000000a0b00003900000000090b041a000000000990004c000015870000c13d00040000000b001d00050000000a001d000600000002001d000800000004001d000700000005001d000100000008001d000200000006001d000300000007001d0000000702000039000000000032041b000000000202041a000000000220004c000015b00000613d21251fcb0000040f0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000502000029000000000012041b0000085e010000410000000402000029000000000012041b00000006010000292125204d0000040f00000008010000290000000001010433000500000001001d000008db0110009c000015980000813d0000000101000039000600000001001d000000000101041a212513890000040f000000200210008c0000000509000029000014fd0000413d0000001f029000390000000502200270000008da02200041000008da03000041000000200490008c0000000002034019000000010300003900000000003004350000001f011000390000000501100270000008da01100041000000000312004b000014fd0000813d000000000002041b0000000102200039000014f80000013d000000200190008c000015110000413d00000001010000390000000000100435000000200200008a000000000329016f000008da020000410000002004000039000000000500001900000007070000290000000808000029000000000635004b00000000068400190000151f0000813d0000000006060433000000000062041b000000200550003900000020044000390000000102200039000015080000013d000000000190004c00000000010000190000000802000029000015170000613d000000200120003900000000010104330000000302900210000000010300008a000000000223022f000000000232013f000000000221016f000000010190021000000007070000290000152a0000013d000000000393004b000015290000813d0000000303900210000000f80330018f000000010400008a000000000334022f000000000343013f0000000004060433000000000334016f000000000032041b0000000102900210000000000112019f0000000602000029000000000012041b0000000001070433000500000001001d000008500110009c000015980000213d0000000201000039000800000001001d000000000101041a212513890000040f000000200210008c0000000306000029000000010700002900000005090000290000154a0000413d0000001f029000390000000502200270000008c802200041000008c803000041000000200490008c0000000002034019000000080300002900000000003004350000001f011000390000000501100270000008c801100041000000000312004b0000154a0000813d000000000002041b0000000102200039000015450000013d000000200190008c0000155d0000413d00000008010000290000000000100435000000200100008a000000000219016f000008c801000041000000200300003900000000040000190000000708000029000000000524004b00000000058300190000156a0000813d0000000005050433000000000051041b000000200440003900000020033000390000000101100039000015540000013d000000000190004c00000000010000190000000702000029000015630000613d000000200120003900000000010104330000000302900210000000010300008a000000000223022f000000000232013f000000000121016f0000000102900210000015760000013d000000000292004b000015740000813d0000000302900210000000f80220018f000000010300008a000000000223022f000000000232013f0000000003050433000000000223016f000000000021041b00000001019002100000000602000029000000000121019f0000000802000029000000000012041b000000000107041a000001000200008a000000000121016f0000000203000029000000ff0330018f000000000131019f000000000017041b0000001101000039000000000061041b000000000100041a000000000121016f00000001011001bf000000000010041b000000000001042d000000400100043d0000006402100039000008570300004100000000003204350000004402100039000008580300004100000000003204350000002402100039000000230300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000084020000392125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000400100043d0000006402100039000008540300004100000000003204350000004402100039000008550300004100000000003204350000002402100039000000240300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000084020000392125033c0000040f000000400100043d0000006402100039000008650300004100000000003204350000004402100039000008660300004100000000003204350000002402100039000000300300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000084020000392125033c0000040f000000000110004c000015c40000613d000000000001042d000000400100043d0000004402100039000008de03000041000000000032043500000024021000390000000a0300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000064020000392125033c0000040f0000084f022001970000000000200435000000200010043f000000400200003900000000010000192125030b0000040f000000000001042d000c00000000000200000000070100190000000501000039000300000001001d000000000601041a000000400800043d00000064018000390000000000410435000008df01000041000000000018043500000000010004100000084f01100197000000040580003900000000001504350000084f033001970000004401800039000800000003001d00000000003104350000084f022001970000002401800039000a00000002001d000000000021043500000000010004140000084f02600197000000040320008c000900000004001d000016000000613d0000008404000039000000200600003900000000030800190000000005080019000700000007001d000600000008001d2125029d0000040f000000060800002900000007070000290000000904000029000000000110004c0000173b0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001830019000000000331004b00000000030000190000000103004039000008500510009c0000172d0000213d00000001033001900000172d0000c13d000000400010043f0000001f0220008c0000172a0000a13d0000000002080433000000000320004c0000175b0000c13d00000008020000290000000a03000029000000000223004b000017610000613d000000010100008a000600000001001d00000000020004150000000c0220008a00000020022000c90000084f01700197000500000001001d000000000131004b000016370000613d0000000a0100002900000000001004350000000f01000039000000200010043f0000004002000039000700000002001d00000000010000192125030b0000040f00000005020000290000000000200435000000200010043f000000000100001900000007020000292125030b0000040f000000090400002900000000020004150000000b0220008a00000020022000c9000000000101041a000600000001001d000000000141004b000017340000413d000000200120011a000000060200002900000000014200550000000a0100002900000000001004350000000e01000039000700000001001d000000200010043f000000400200003900000000010000192125030b0000040f000000000201041a0000000901000029000400000002001d000000000112004b000017340000413d000000080100002900000000001004350000000701000029000000200010043f000000400200003900000000010000192125030b0000040f0000000903000029000000000101041a0000000002310019000200000002001d000000000112004b000000000100001900000001010040390000000101100190000017340000c13d0000000a0100002900000000001004350000000701000029000000200010043f0000004002000039000100000002001d00000000010000192125030b0000040f000000090300002900000004020000290000000002320049000000000021041b000000080100002900000000001004350000000701000029000000200010043f000000000100001900000001020000292125030b0000040f0000000202000029000000000021041b000000010100008a0000000602000029000000000112004b0000000001020019000016840000613d00000009020000290000000001210049000600000001001d0000000a0100002900000000001004350000000f01000039000000200010043f0000004002000039000400000002001d00000000010000192125030b0000040f00000005020000290000000000200435000000200010043f000000000100001900000004020000292125030b0000040f0000000602000029000000000021041b0000001201000039000500000001001d000000000101041a000008b00200004100000000002004390000084f01100197000600000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00000009030000290000172a0000613d000000400500043d000008b101000041000000000015043500000044025000390000000001000414000000000032043500000024025000390000000a0300002900000000003204350000000402500039000008b20300004100000000003204350000000602000029000000040320008c000016aa0000613d00000064040000390000000003050019000600000005001d000000060500002900000000060000192125029d0000040f0000000605000029000000000110004c0000173b0000613d000008500150009c0000172d0000213d000000400050043f0000000501000029000000000101041a000008b00200004100000000002004390000084f01100197000600000001001d000000040010044300008002010000390000002402000039212503200000040f0000000904000029000000000110004c0000172a0000613d000000400500043d000008bd0100004100000000001504350000004402500039000000000100041400000000004204350000002402500039000000080300002900000000003204350000000402500039000008b20300004100000000003204350000000602000029000000040320008c000016d30000613d00000064040000390000000003050019000600000005001d000000060500002900000000060000192125029d0000040f00000006050000290000000904000029000000000110004c0000173b0000613d000008500150009c0000172d0000213d000000400050043f00000000004504350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0350009c00000000010540190000004001100210000000c002200210000000000112019f000008b3011001c70000800d020000390000000303000039000008b4040000410000000a0500002900000008060000292125211b0000040f00000001012001900000172a0000613d0000000301000029000000000101041a000900000001001d0000000a0100002900000000001004350000000701000029000000200010043f0000004002000039000600000002001d00000000010000192125030b0000040f000000000101041a000500000001001d000000080100002900000000001004350000000701000029000000200010043f000000000100001900000006020000292125030b0000040f000000000101041a000700000001001d000008b001000041000000000010043900000009010000290000084f01100197000900000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c0000172a0000613d000000400500043d000008b5010000410000000000150435000000640250003900000000010004140000000703000029000000000032043500000044025000390000000503000029000000000032043500000024025000390000000803000029000000000032043500000004025000390000000a0300002900000000003204350000000902000029000000040320008c000017260000613d00000084040000390000000003050019000a00000005001d0000000a0500002900000000060000192125029d0000040f0000000a05000029000000000110004c0000173b0000613d000008500150009c0000172d0000213d000000400050043f000000000001042d000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f00000005044002720000174a0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000017420000413d000000000530004c000017590000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f000008e00300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f000008e102000041000000000021043500000004020000392125033c0000040f000b000000000002000400000001001d000500000002001d000008db0120009c000017f50000813d000000050100002900000005011002100000003f02100039000000200300008a000000000232016f000000400800043d0000000002280019000000000382004b00000000030000190000000103004039000008500420009c000017f50000213d0000000103300190000017f50000c13d000000400020043f0000000502000029000000000028043500000020098000390000000002000019000000000312004b000017930000813d000000400300043d000008e20430009c000017f50000213d0000004004300039000000400040043f00000000040000310000000204400367000000000500001900000005065002100000000007630019000000000664034f000000000606043b00000000006704350000000105500039000000020650008c000017870000413d0000000004290019000000000034043500000020022000390000177d0000013d0000000e01000039000300000001001d0000004001000039000900000001001d0000001001000039000a00000001001d0000000003000019000200000008001d000100000009001d0000000501000029000000000113004b000017ec0000813d0000000501300210000000040200002900000000022100190000000202200367000000000402043b000008530240009c000017fc0000813d0000000002080433000000000232004b000017ee0000a13d000700000003001d0000000001190019000600000001001d0000000001010433000800000001001d00000000004004350000000301000029000000200010043f00000000010000190000000902000029000b00000004001d2125030b0000040f000000000101041a000000080200002900000000001204350000000b0100002900000000001004350000000a01000029000000200010043f000000000100001900000009020000292125030b0000040f0000000101100039000000000101041a000000000110004c0000000001000019000017e00000613d0000000b0100002900000000001004350000000a01000029000000200010043f000000400200003900000000010000192125030b0000040f000000000101041a0000085e231000d1000000000210004c000017d20000613d00000000211300d90000085e0110009c000018060000c13d000800000003001d0000000b0100002900000000001004350000000a01000029000000200010043f000000400200003900000000010000192125030b0000040f0000000101100039000000000101041a000000000210004c000017ff0000613d000000080200002900000000211200d9000000020800002900000000020804330000000703000029000000000232004b0000000109000029000017ee0000a13d000000060200002900000000020204330000002002200039000000000012043500000001033000390000179c0000013d0000000001080019000000000001042d000008640100004100000000001004350000003201000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000001201000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f00010000000000020000001301000039000000000201041a000000400300043d000008d401000041000000000013043500000004013000390000000004000410000000000041043500000000010004140000084f02200197000000040420008c000018220000613d00000024040000390000002006000039000100000003001d0000000105000029212502d40000040f0000000103000029000000000110004c0000183f0000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000008500420009c000018350000213d0000000104500190000018350000c13d000000400020043f0000001f0110008c0000183c0000a13d0000000001030433000000000001042d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000000000100001900000000020000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f00000005044002720000184e0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000018460000413d000000000530004c0000185d0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f0000084f0110019700000000001004350000001001000039000000200010043f000000400200003900000000010000192125030b0000040f000000000301041a000000000230004c0000000002000019000018750000613d0000000a02000039000000000402041a00000000523400a900000000533200d9000000000343004b000018770000c13d0000000101100039000000000101041a000000000310004c0000187e0000613d00000000121200d90000000001020019000000000001042d000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000001201000039000000040010043f000000240200003900000000010000192125033c0000040f0002000000000002000000000100041a000100000001001d000000ff0110018f212515c10000040f000001000100008a000200000001001d0000000102000029000000000112016f000000000010041b212518c40000040f212518970000040f000000000200041a0000000203000029000000000232016f00000001022001bf000000000020041b000000000001042d00010000000000020000000d01000039000000000201041a000000000120004c000018ba0000613d000100000002001d2125180d0000040f0000000b02000039000000000202041a0000000001120019000000000221004b000000000200001900000001020040390000000102200190000018bd0000c13d0000000c02000039000000000302041a000000000231004b000018bd0000413d000000000531004900000001040000390000085e625000d1000000000631004b000018b30000613d00000000545200d90000085e0440009c0000000004000019000000010400c039000000000131004b000018b70000613d0000000101400190000018bd0000c13d000000010100002900000000211200d9000018bc0000013d0000000701000039000000000101041a000000000001042d000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f00090000000000020000000901000039000800000001001d000000000101041a000900000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000902000029000000000112004b0000199e0000613d2125180d0000040f00000000020100190000000a01000039000300000001001d000000000101041a000700000001001d0000000601000039000000000601041a0000000b01000039000200000001001d000000000701041a0000000c01000039000100000001001d000000000501041a000000400300043d000008a70100004100000000001304350000000404300039000000000100041400000000002404350000004402300039000400000005001d0000000000520435000000240230003900000000007204350000084f02600197000000040420008c000600000007001d000018f70000613d000000640400003900000020060000390000000005030019000500000003001d212502d40000040f00000005030000290000000607000029000000000110004c000019bd0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600410018f0000000001340019000000000441004b00000000050000190000000105004039000008500410009c000019a90000213d0000000104500190000019a90000c13d000000400010043f0000001f0220008c0000199f0000a13d0000000002030433000500000002001d000008e30220009c000019b00000813d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000903000029000000000231004b0000000607000029000019a20000413d000000000331004900000005010000290000085e0210004100000001013001900000085e01000041000000000102c019000000020430008c0000193a0000413d00000000452200a9000000000420004c000019250000613d000008e40450009c0000199f0000213d00000000642500d9000000000224004b0000199f0000c13d0000000104300270000008e5025000410000085e6220012a000000020330019000000000030400190000191b0000613d00000000631200a9000008e50550009c000019310000813d000008e40130009c000019360000a13d0000199f0000013d000008e40530009c0000199f0000213d00000000652300d9000000000115004b0000199f0000c13d000008e5013000410000085e3110012a00000000030400190000191b0000013d00000000327100a9000000000310004c000019400000613d00000000431200d9000000000373004b000019a20000c13d0000085e2620012a000000000276004b000019a20000413d00000000057600490000000802000039000000000302041a00000000425300a9000000000430004c0000194c0000613d00000000433200d9000000000353004b000019a20000c13d0000085e3220012a00000004030000290000000003320019000900000003001d000000000223004b000000000200001900000001020040390000000102200190000019a20000c13d000000070200002900000000232100a9000000000210004c0000195d0000613d00000000211300d90000000702000029000000000121004b000019a20000c13d000500000005001d0000085d0100004100000000001004390000800b010000390000000402000039000700000006001d000600000003001d212503200000040f0000000802000029000000000012041b00000006010000290000085e1210012a0000000301000029000800000002001d000000000021041b00000002010000290000000702000029000000000021041b00000001010000290000000902000029000000000021041b0000000501000039000000000101041a000900000001001d212518970000040f000008b002000041000000000020043900000009020000290000084f02200197000900000002001d0000000400200443000700000001001d00008002010000390000002402000039212503200000040f000000000110004c0000199f0000613d000000400500043d000008e601000041000000000015043500000044025000390000000001000414000000070300002900000000003204350000002402500039000000080300002900000000003204350000000402500039000000050300002900000000003204350000000902000029000000040320008c0000199b0000613d00000064040000390000000003050019000900000005001d000000090500002900000000060000192125029d0000040f0000000905000029000000000110004c000019bd0000613d000008500150009c000019a90000213d000000400050043f000000000001042d000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000004402100039000008e703000041000000000032043500000024021000390000001c0300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000064020000392125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000019cc0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000019c40000413d000000000530004c000019db0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f0005000000000002000200000002001d000300000001001d0000001301000039000000000201041a000000400300043d000008d401000041000000000013043500000000010004100000084f0410019700000004053000390000000001000414000400000004001d00000000004504350000084f02200197000000040420008c000500000002001d000019f80000613d000000240400003900000020060000390000000005030019000100000003001d212502d40000040f00000001030000290000000502000029000000000110004c00001a780000613d0000000101000031000000200410008c000000200400003900000000040140190000001f04400039000000600440018f0000000005340019000000000445004b00000000060000190000000106004039000008500450009c00001a710000213d000000010460019000001a710000c13d000000400050043f0000001f0110008c00001a6e0000a13d0000000001030433000100000001001d000008b0010000410000000000100439000000040020044300008002010000390000002402000039212503200000040f0000000502000029000000000110004c00001a6e0000613d000000400500043d000008e8010000410000000000150435000000440350003900000000010004140000000204000029000000000043043500000024035000390000000404000029000000000043043500000003030000290000084f0330019700000004045000390000000000340435000000040320008c00001a300000613d000200000004001d00000064040000390000000003050019000300000005001d000000030500002900000000060000192125029d0000040f000000020400002900000003050000290000000502000029000000000110004c00001a780000613d000008500150009c00001a710000213d000000400050043f000000010100003200001a470000613d000000200110008c00001a6e0000c13d000000030100036700000000050000190000000503500210000000000431034f000000000404043b0000000000430435000000010550003a00000000030000190000000103006039000000010330019000001a390000c13d000000400500043d0000000001000433000000000110004c00001a9f0000613d0000000404500039000008d4010000410000000000150435000000000100041400000004030000290000000000340435000000040320008c00001a570000613d000000240400003900000020060000390000000003050019000300000005001d0000000305000029212502d40000040f0000000305000029000000000110004c00001a780000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f0000000002530019000000000332004b00000000030000190000000103004039000008500420009c00001a710000213d000000010330019000001a710000c13d000000400020043f000000200110008c00001a6e0000413d00000000010504330000000103000029000000000231004b00001a980000413d0000000001310049000000000001042d000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001a870000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001a7f0000413d000000000530004c00001a960000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f0000004401500039000008e902000041000000000021043500000024015000390000001802000039000000000021043500000856010000410000000000150435000000040150003900000020020000390000000000210435000000640200003900000000010500192125033c0000040f0003000000000002000100000002001d000200000001001d0000001301000039000000000101041a000008b00200004100000000002004390000084f01100197000300000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00001ae80000613d000000400300043d000008d5010000410000000000130435000000240230003900000000010004140000000104000029000000000042043500000002020000290000084f02200197000000040430003900000000002404350000000302000029000000040420008c00001ad20000613d0000004404000039000300000003001d000000030500002900000000060000192125029d0000040f0000000303000029000000000110004c00001af20000613d000008db0130009c00001aeb0000813d000000400030043f000000010100003200001ae70000613d000000200110008c00001ae80000c13d000000030100036700000000020000190000000503200210000000000431034f000000000404043b0000000000430435000000010220003a00000000030000190000000103006039000000010330019000001adb0000c13d0000000001000433000000000110004c00001b120000613d000000000001042d000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001b010000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001af90000413d000000000530004c00001b100000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f000000400100043d0000004402100039000008ea0300004100000000003204350000002402100039000000190300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000064020000392125033c0000040f000c0000000000020000000504000039000700000004001d000000000504041a000000400700043d0000006404700039000900000003001d0000000000340435000008eb03000041000000000037043500000000030004100000084f0430019700000004037000390000000000430435000b00000002001d0000084f032001970000004404700039000a00000003001d0000000000340435000c00000001001d0000084f031001970000002401700039000500000003001d000000000031043500000000010004140000084f02500197000000040320008c00001b450000613d0000008404000039000000200600003900000000030700190000000005070019000800000007001d2125029d0000040f0000000807000029000000000110004c00001c300000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001730019000000000331004b00000000030000190000000103004039000008500410009c00001c220000213d000000010330019000001c220000c13d000000400010043f0000001f0220008c00001c1f0000a13d0000000002070433000000000320004c00001c500000c13d0000000901000039000000000101041a000800000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000802000029000000000112004b00001c560000c13d0000000b010000292125185f0000040f000b00000001001d000000010300008a0000000902000029000000000332004b00000000020160190000000c01000029212519dd0000040f000c00000001001d0000000b02000029000000000112004b00001c180000413d0000000b01000039000800000001001d000000000201041a0000000c01000029000600000002001d000000000112004b00001c180000413d0000000c010000290000000b020000290000000002120049000900000002001d0000000a0100002900000000001004350000001001000039000300000001001d000000200010043f0000004002000039000400000002001d00000000010000192125030b0000040f0000000902000029000000000021041b0000000a0100002900000000001004350000000301000029000000200010043f000000000100001900000004020000292125030b0000040f0000000a03000039000000000203041a0000000101100039000000000021041b0000000c0500002900000006010000290000000001510049000200000001001d0000000802000029000000000012041b00000009010000290000085e121000d1000800000002001d0000001201000039000100000001001d000000000101041a0000084f041001970000000b01000029000000000151004b00001ba70000613d0000000901000029000000080200002900000000211200d90000085e0110009c00001c180000c13d000300000003001d000000000103041a000600000001001d000000000110004c00001c290000613d000008b0010000410000000000100439000000040040044300008002010000390000002402000039000400000004001d212503200000040f000000000110004c00001c1f0000613d000000400500043d000008ee0100004100000000001504350000000801000029000000060200002900000000122100d900000044035000390000000001000414000000000023043500000024025000390000000a0300002900000000003204350000000402500039000008be0300004100000000003204350000000403000029000000040230008c000000000203001900001bd10000613d00000064040000390000000003050019000600000005001d000000060500002900000000060000192125029d0000040f0000000605000029000000000110004c00001c300000613d000008500150009c00001c220000213d000000400050043f0000000701000029000000000101041a0000084f041001970000000c010000290000000b02000029000000000112004b000000030300002900001be10000613d0000000901000029000000080200002900000000211200d90000085e0110009c00001c180000c13d000000000103041a000b00000001001d000000000110004c00001c290000613d000008b0010000410000000000100439000000040040044300008002010000390000002402000039000700000004001d212503200000040f000000000110004c00001c1f0000613d000000400500043d000008ef01000041000000000015043500000008010000290000000b0200002900000000122100d9000000a4035000390000000001000414000000000023043500000084025000390000000203000029000000000032043500000064025000390000000903000029000000000032043500000044025000390000000c03000029000000000032043500000024025000390000000a0300002900000000003204350000000402500039000000050300002900000000003204350000000703000029000000040230008c000000000203001900001c130000613d000000c4040000390000000003050019000b00000005001d0000000b0500002900000000060000192125029d0000040f0000000b05000029000000000110004c00001c300000613d000008500150009c00001c220000213d000000400050043f0000000c01000029000000000001042d000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000000101000029000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001c3f0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001c370000413d000000000530004c00001c4e0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f000008ec0300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f000000400100043d000008ed02000041000000000021043500000004020000392125033c0000040f000a0000000000020000000505000039000600000005001d000000000505041a000000400700043d0000008406700039000300000003001d0000000000360435000008f0030000410000000000370435000900000002001d0000084f032001970000006402700039000700000003001d0000000000320435000800000001001d0000084f031001970000004401700039000500000003001d00000000003104350000084f03400197000a00000003001d000000240170003900000000003104350000000001000410000100000001001d0000084f021001970000000401700039000200000002001d000000000021043500000000010004140000084f02500197000000040320008c00001c860000613d000000a404000039000000200600003900000000030700190000000005070019000400000007001d2125029d0000040f0000000407000029000000000110004c00001d9a0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001730019000000000331004b00000000030000190000000103004039000008500410009c00001d930000213d000000010330019000001d930000c13d000000400010043f0000001f0220008c00001d900000a13d0000000002070433000000000320004c00001dba0000c13d0000000901000039000000000101041a000400000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f000000400300043d0000000402000029000000000112004b00001dc00000c13d000008f301000041000000000013043500000000010004140000000a02000029000000040420008c00001cb40000613d00000004040000390000002006000039000400000003001d0000000405000029212502d40000040f0000000403000029000000000110004c00001d9a0000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000008500420009c00001d930000213d000000010450019000001d930000c13d000000400020043f000000200110008c00001d900000413d0000000001030433000400000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000402000029000000000112004b00001dc50000c13d00000009010000290000000802000029000000000121013f0000084f01100198000000030300002900001dca0000613d000000000130004c00001dcf0000613d000000010100008a000000000113004b00001dd40000613d0000000801000029000000090200002921251b200000040f00000000040100190000000601000029000000000201041a000000400300043d000008f5010000410000000000130435000000240630003900000000010004140000000a0500002900000000005604350000000407300039000000020600002900000000006704350000004406300039000300000004001d00000000004604350000084f02200197000000040420008c00001cf90000613d000000640400003900000040060000390000000005030019000400000003001d212502d40000040f00000004030000290000000a05000029000000000110004c00001d9a0000613d0000000101000031000000400210008c000000400200003900000000020140190000001f02200039000000e00220018f0000000007320019000000000227004b00000000020000190000000102004039000008500470009c00001d930000213d000000010220019000001d930000c13d000000400070043f000000400110008c00001d900000413d0000000001030433000000000110004c00001dd90000c13d00000020013000390000000004010433000008d40100004100000000001704350000000402700039000000000100041400000007030000290000000000320435000000040250008c000400000004001d00001d240000613d00000024040000390000002006000039000000000205001900000000030700190000000005070019000200000007001d212502d40000040f000000020700002900000004040000290000000a05000029000000000110004c00001d9a0000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600220018f0000000008720019000008500280009c00001d930000213d000000400080043f000000200110008c00001d900000413d0000000001070433000000000141004b00001dea0000413d0000000101000029000000000115004b00001d3b0000c13d00000000010500190000000802000029000000090300002921251e050000040f00001d610000013d000008f8010000410000000000180435000000440280003900000000010004140000000000420435000000240280003900000007030000290000000000320435000000040280003900000005030000290000000000320435000000040250008c00001d520000613d00000064040000390000002006000039000000000205001900000000030800190000000005080019000900000008001d2125029d0000040f0000000908000029000000000110004c00001d9a0000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600110018f0000000001810019000008500310009c00001d930000213d000000400010043f000000200220008c00001d900000413d0000000002080433000000000220004c00001df80000c13d0000000601000029000000000101041a000008b00200004100000000002004390000084f01100197000900000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c0000000a03000029000000040400002900001d900000613d000000400500043d000008fa010000410000000000150435000000840250003900000000010004140000000000420435000000640250003900000000003204350000004402500039000000030300002900000000003204350000002402500039000000070300002900000000003204350000000402500039000000050300002900000000003204350000000902000029000000040320008c00001d8c0000613d000000a4040000390000000003050019000a00000005001d0000000a0500002900000000060000192125029d0000040f0000000a05000029000000000110004c00001d9a0000613d000008500150009c00001d930000213d000000400050043f000000000001042d000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001da90000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001da10000413d000000000530004c00001db80000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f000008f10300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f000008f2010000410000000000130435000000040200003900000000010300192125033c0000040f000000400100043d000008f402000041000000000021043500000004020000392125033c0000040f000000400100043d000008fe02000041000000000021043500000004020000392125033c0000040f000000400100043d000008fd02000041000000000021043500000004020000392125033c0000040f000000400100043d000008fc02000041000000000021043500000004020000392125033c0000040f0000006401700039000008f60200004100000000002104350000004401700039000008f702000041000000000021043500000024017000390000003302000039000000000021043500000856010000410000000000170435000000040170003900000020020000390000000000210435000000840200003900000000010700192125033c0000040f0000004401800039000008fb02000041000000000021043500000024018000390000001802000039000000000021043500000856010000410000000000180435000000040180003900000020020000390000000000210435000000640200003900000000010800192125033c0000040f0000004402100039000008f90300004100000000003204350000002402100039000000140300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000064020000392125033c0000040f000d0000000000020000000505000039000600000005001d000000000605041a000000400700043d0000008405700039000900000004001d00000000004504350000084f0110019700000024057000390000000000150435000008ff0100004100000000001704350000084f033001970000006401700039000d00000003001d00000000003104350000084f022001970000004401700039000c00000002001d00000000002104350000000001000410000400000001001d0000084f021001970000000401700039000300000002001d000000000021043500000000010004140000084f02600197000000040320008c00001e2d0000613d000000a404000039000000200600003900000000030700190000000005070019000b00000007001d2125029d0000040f0000000b07000029000000000110004c00001f900000613d0000000102000031000000200120008c000000200100003900000000010240190000001f01100039000000600310018f0000000001730019000000000331004b00000000030000190000000103004039000008500410009c00001f820000213d000000010330019000001f820000c13d000000400010043f0000001f0220008c00001f7f0000a13d0000000002070433000000000320004c00001fb00000c13d0000000d020000290000000c03000029000000000232004b00001fb60000613d000008ad0210009c00001f820000213d0000002002100039000000400020043f000008cb0200004100000000002104350000000903000029000008cb213000d1000000000230004c00001e530000613d000000090200002900000000322100d9000008cb0220009c00001f890000c13d0000085e1210012a000a00000002001d212518970000040f0000000002010019000000400100043d000008ad0310009c00001f820000213d0000002003100039000000400030043f00000000002104350000000a02000029212520e00000040f00000000010104330000085e1310012a0000000c01000039000000000201041a000100000003001d0000000003320019000700000003001d000000000223004b00000000020000190000000102004039000000010220019000001f890000c13d0000000702000029000000000021041b0000000d01000039000000000201041a0000000a03000029000000000332004b00001f890000413d0000000a030000290000000002320049000000000021041b0000000d0100002900000000001004350000000e01000039000b00000001001d000000200010043f0000004002000039000800000002001d00000000010000192125030b0000040f0000000d0200002900000000002004350000000b02000029000000200020043f000500000001001d000000000100001900000008020000292125030b0000040f000000000101041a0000000902000029000000000221004b00001f890000413d00000009020000290000000a030000290000000003320049000800000003001d00000000012100490000000502000029000000000012041b0000000c0100002900000000001004350000000b01000029000000200010043f0000004002000039000500000002001d00000000010000192125030b0000040f0000000c0200002900000000002004350000000b02000029000000200020043f000200000001001d000000000100001900000005020000292125030b0000040f000000000201041a00000008010000290000000001120019000000000221004b00000000020000190000000102004039000000010220019000001f890000c13d0000000b020000290000000202000029000000000012041b0000001201000039000200000001001d000000000101041a000008b00200004100000000002004390000084f01100197000500000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00001f7f0000613d000000400500043d000008b1010000410000000000150435000000440250003900000000010004140000000903000029000000000032043500000024025000390000000d0300002900000000003204350000000402500039000008b20300004100000000003204350000000502000029000000040320008c00001ed20000613d00000064040000390000000003050019000900000005001d000000090500002900000000060000192125029d0000040f0000000905000029000000000110004c00001f900000613d000008500150009c00001f820000213d000000400050043f0000000201000029000000000101041a000008b00200004100000000002004390000084f01100197000900000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00001f7f0000613d000000400500043d000008bd010000410000000000150435000000440250003900000000010004140000000803000029000000000032043500000024025000390000000c0300002900000000003204350000000402500039000008b20300004100000000003204350000000902000029000000040320008c00001efa0000613d00000064040000390000000003050019000900000005001d000000090500002900000000060000192125029d0000040f0000000905000029000000000110004c00001f900000613d000008500150009c00001f820000213d000000400050043f000000080100002900000000001504350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0350009c00000000010540190000004001100210000000c002200210000000000112019f000008b3011001c70000800d020000390000000303000039000008b4040000410000000d050000290000000c060000292125211b0000040f000000010120019000001f7f0000613d0000000601000029000000000101041a000900000001001d0000000d0100002900000000001004350000000b01000029000000200010043f0000004002000039000800000002001d00000000010000192125030b0000040f000000000101041a000600000001001d0000000c0100002900000000001004350000000b01000029000000200010043f000000000100001900000008020000292125030b0000040f000000000101041a000800000001001d000008b001000041000000000010043900000009010000290000084f01100197000b00000001001d000000040010044300008002010000390000002402000039212503200000040f000000000110004c00001f7f0000613d000000400500043d000008b5010000410000000000150435000000640250003900000000010004140000000803000029000000000032043500000044025000390000000603000029000000000032043500000024025000390000000c03000029000000000032043500000004025000390000000d0300002900000000003204350000000b02000029000000040320008c00001f4e0000613d00000084040000390000000003050019000c00000005001d0000000c0500002900000000060000192125029d0000040f0000000c05000029000000000110004c00001f900000613d000008500150009c00001f820000213d000000400050043f0000000a0100002900000000001504350000084b0100004100000000020004140000084b0320009c00000000020180190000084b0350009c00000000010540190000004001100210000000c002200210000000000112019f000008b3011001c70000800d020000390000000303000039000008b4040000410000000d0500002900000004060000292125211b0000040f000000010120019000001f7f0000613d000000400100043d000000400210003900000007030000290000000000320435000000200210003900000001030000290000000000320435000000030200002900000000002104350000084b0200004100000000030004140000084b0430009c00000000030280190000084b0410009c00000000010280190000004001100210000000c002300210000000000112019f000008b7011001c70000800d020000390000000103000039000008d1040000412125211b0000040f000000010120019000001f7f0000613d000000000001042d000000000100001900000000020000192125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200001f9f0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00001f970000413d000000000530004c00001fae0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f000009000300004100000000003104350000000403100039000000000023043500000024020000392125033c0000040f0000090102000041000000000021043500000004020000392125033c0000040f000000000110004c00001fbd0000613d000000000001042d000000400100043d0000004402100039000008dc03000041000000000032043500000024021000390000001c0300003900000000003204350000085602000041000000000021043500000004021000390000002003000039000000000032043500000064020000392125033c0000040f00040000000000020000000302000039000000000202041a00000008022002700000084f022001970000000003000411000000000223004b000020210000c13d0000000502000039000300000002001d000000000202041a000000400300043d000008590400004100000000004304350000084f02200197000200000002001d00000000020004140000084f01100197000400000001001d000000040110008c00001fea0000613d0000000404000039000000200600003900000000010200190000000402000029000100000003001d0000000105000029212502d40000040f0000000103000029000000000110004c0000202d0000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000008500420009c000020260000213d0000000104500190000020260000c13d000000400020043f0000001f0110008c0000201e0000a13d0000000001030433000000000210004c0000000002000019000000010200c039000000000221004b0000201e0000c13d21251fba0000040f0000000302000029000000000102041a0000085a011001970000000403000029000000000131019f000000000012041b000000400100043d00000020021000390000000000320435000000020200002900000000002104350000084b0200004100000000030004140000084b0430009c00000000030280190000084b0410009c00000000010280190000004001100210000000c002300210000000000112019f0000085b011001c70000800d0200003900000001030000390000085c040000412125211b0000040f00000001012001900000201e0000613d000000000001042d000000000100001900000000020000192125033c0000040f000000400100043d0000090202000041000000000021043500000004020000392125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f00000005044002720000203c0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000020340000413d000000000530004c0000204b0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f0004000000000002000400000001001d0000000301000039000000000101041a00000008011002700000084f011001970000000002000411000000000112004b000020af0000c13d0000000901000039000000000101041a000300000001001d0000085d0100004100000000001004390000800b010000390000000402000039212503200000040f0000000302000029000000000112004b000020b40000c13d0000000601000039000300000001001d000000000101041a000000400300043d0000085f0200004100000000002304350000084f01100197000200000001001d000000000100041400000004020000290000084f02200197000400000002001d000000040220008c000020780000613d000000040400003900000020060000390000000402000029000100000003001d0000000105000029212502d40000040f0000000103000029000000000110004c000020c00000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000008500420009c000020b90000213d0000000104500190000020b90000c13d000000400020043f0000001f0110008c000020ac0000a13d0000000001030433000000000210004c0000000002000019000000010200c039000000000221004b000020ac0000c13d21251fba0000040f0000000302000029000000000102041a0000085a011001970000000403000029000000000131019f000000000012041b000000400100043d00000020021000390000000000320435000000020200002900000000002104350000084b0200004100000000030004140000084b0430009c00000000030280190000084b0410009c00000000010280190000004001100210000000c002300210000000000112019f0000085b011001c70000800d02000039000000010300003900000860040000412125211b0000040f0000000101200190000020ac0000613d000000000001042d000000000100001900000000020000192125033c0000040f000000400100043d0000090302000041000000000021043500000004020000392125033c0000040f000000400100043d0000090402000041000000000021043500000004020000392125033c0000040f000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f0000000302000367000000400100043d00000001040000310000001f0340018f0000000504400272000020cf0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000020c70000413d000000000530004c000020de0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000312125033c0000040f000000400300043d000008dd0430009c000020f40000813d0000002004300039000000400040043f0000000000030435000000000101043300000000432100a9000000000410004c000020ed0000613d00000000411300d9000000000121004b000020fb0000c13d000000400100043d000008ad0210009c000020f40000213d0000002002100039000000400020043f0000000000310435000000000001042d000008640100004100000000001004350000004101000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f0000085e431000d1000000000410004c000021080000613d00000000411300d90000085e0110009c000021140000c13d0000000001020433000000000210004c0000210d0000613d00000000211300d9000000000001042d000008640100004100000000001004350000001201000039000000040010043f000000240200003900000000010000192125033c0000040f000008640100004100000000001004350000001101000039000000040010043f000000240200003900000000010000192125033c0000040f0000211e002104210000000102000039000000000001042d00000000020000190000211d0000013d00002123002104230000000102000039000000000001042d0000000002000019000021220000013d0000212500000432000021260001042e0000212700010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff000000000000007f8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000ff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000010000000000000000000000000000000000000000726b6574000000000000000000000000000000000000000000000000000000006f6e6c792061646d696e206d617920696e697469616c697a6520746865206d6108c379a0000000000000000000000000000000000000000000000000000000006e636500000000000000000000000000000000000000000000000000000000006d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f007e3dd200000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000400000000000000000000000007ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320000000000000000000000000000000000000000000000000de0b6b3a76400002191f92a00000000000000000000000000000000000000000000000000000000edffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f92618160ddd00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffff00000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000006561746572207468616e207a65726f2e00000000000000000000000000000000696e697469616c2065786368616e67652072617465206d757374206265206772020000000000000000000000000000000000000000000000000000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000095ea7b3000000000000000000000000000000000000000000000000000000000cf4ceb4000000000000000000000000000000000000000000000000000000000d8ef28b000000000000000000000000000000000000000000000000000000000e75270200000000000000000000000000000000000000000000000000000000173b99040000000000000000000000000000000000000000000000000000000017bfdfbc0000000000000000000000000000000000000000000000000000000018160ddd00000000000000000000000000000000000000000000000000000000182df0f5000000000000000000000000000000000000000000000000000000001be19560000000000000000000000000000000000000000000000000000000002138ec400000000000000000000000000000000000000000000000000000000023b872dd000000000000000000000000000000000000000000000000000000002608f818000000000000000000000000000000000000000000000000000000002678224700000000000000000000000000000000000000000000000000000000313ce567000000000000000000000000000000000000000000000000000000003af9e669000000000000000000000000000000000000000000000000000000003b1d21a2000000000000000000000000000000000000000000000000000000003e941010000000000000000000000000000000000000000000000000000000004576b5db0000000000000000000000000000000000000000000000000000000047bd371800000000000000000000000000000000000000000000000000000000558e889d000000000000000000000000000000000000000000000000000000005fe3b56700000000000000000000000000000000000000000000000000000000601a0bf1000000000000000000000000000000000000000000000000000000006752e7020000000000000000000000000000000000000000000000000000000069ab3250000000000000000000000000000000000000000000000000000000006c540baf000000000000000000000000000000000000000000000000000000006f307dc30000000000000000000000000000000000000000000000000000000070a082310000000000000000000000000000000000000000000000000000000073acee9800000000000000000000000000000000000000000000000000000000852a12e3000000000000000000000000000000000000000000000000000000008f840ddd0000000000000000000000000000000000000000000000000000000095d89b410000000000000000000000000000000000000000000000000000000095dd9193000000000000000000000000000000000000000000000000000000009d4de34a00000000000000000000000000000000000000000000000000000000a0712d6800000000000000000000000000000000000000000000000000000000a2d57df100000000000000000000000000000000000000000000000000000000a6afed9500000000000000000000000000000000000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000aa5af0fd00000000000000000000000000000000000000000000000000000000ae9d70b000000000000000000000000000000000000000000000000000000000b2a02ff100000000000000000000000000000000000000000000000000000000b71d1a0c00000000000000000000000000000000000000000000000000000000bc30a61800000000000000000000000000000000000000000000000000000000bd6d894d00000000000000000000000000000000000000000000000000000000c37f68e200000000000000000000000000000000000000000000000000000000c5ebeaec00000000000000000000000000000000000000000000000000000000d69205c000000000000000000000000000000000000000000000000000000000db006a7500000000000000000000000000000000000000000000000000000000dd62ed3e00000000000000000000000000000000000000000000000000000000e9c714f200000000000000000000000000000000000000000000000000000000f2b3abbd00000000000000000000000000000000000000000000000000000000f3fdb15a00000000000000000000000000000000000000000000000000000000f5e3c46200000000000000000000000000000000000000000000000000000000f851a44000000000000000000000000000000000000000000000000000000000f8f9da2800000000000000000000000000000000000000000000000000000000fca7820b00000000000000000000000000000000000000000000000000000000fe9c44ae240b6af600000000000000000000000000000000000000000000000000000000fbf94d6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640001aaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460e2e441e60000000000000000000000000000000000000000000000000000000015f2405300000000000000000000000000000000000000000000000000000000a6afed95000000000000000000000000000000000000000000000000000000007dd4936e00000000000000000000000000000000000000000000000000000000f9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dcca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a96e893ca400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdfeabe7d9100000000000000000000000000000000000000000000000000000000480f4247000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83009c111600000000000000000000000000000000000000000000000000000000535550504c5900000000000000000000000000000000000000000000000000000200000000000000000000000000000000000020000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef085b7f0800000000000000000000000000000000000000000000000000000000ac6a4069000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000000000000000000000e5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92951dff98900000000000000000000000000000000000000000000000000000000da3d454c00000000000000000000000000000000000000000000000000000000918db40f000000000000000000000000000000000000000000000000000000003a36318400000000000000000000000000000000000000000000000000000000dd56b3f200000000000000000000000000000000000000000000000000000000424f52524f570000000000000000000000000000000000000000000000000000f709dfcd0000000000000000000000000000000000000000000000000000000048c25881000000000000000000000000000000000000000000000000000000005cb56c2b00000000000000000000000000000000000000000000000000000000b8168816000000000000000000000000000000000000000000000000000000004ef4c3e10000000000000000000000000000000000000000000000000000000049abd4fd0000000000000000000000000000000000000000000000000000000038d88597000000000000000000000000000000000000000000000000000000004c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f6a6c276c00000000000000000000000000000000000000000000000000000000405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace97b5cfcd0000000000000000000000000000000000000000000000000000000091240a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006379da05b60000dff50cb0000000000000000000000000000000000000000000000000000000003bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177ef1a5300a000000000000000000000000000000000000000000000000000000003345e9990000000000000000000000000000000000000000000000000000000038acf79900000000000000000000000000000000000000000000000000000000a91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5616e20737765657020746f6b656e7300000000000000000000000000000000004345726332303a3a7377656570546f6b656e3a206f6e6c792061646d696e206370a0823100000000000000000000000000000000000000000000000000000000a9059cbb000000000000000000000000000000000000000000000000000000007020756e6465726c79696e6720746f6b656e00000000000000000000000000004345726332303a3a7377656570546f6b656e3a2063616e206e6f742073776565f7e5e6d0000000000000000000000000000000000000000000000000000000008c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf600000000000000000000000000000000000000000000000100000000000000006d61726b6572206d6574686f642072657475726e65642066616c736500000000000000000000000000000000000000000000000000000000ffffffffffffffe072652d656e746572656400000000000000000000000000000000000000000000bdcdc25800000000000000000000000000000000000000000000000000000000113a84ee000000000000000000000000000000000000000000000000000000008cd22d1900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf0000000000000000000000000000000000000000000000000000048c27395001fffffffffffffffffffffffffffffffffffffffffffffffff90fa4a62c4dffff00000000000000000000000000000000000000000000000006f05b59d3b200005736de3c00000000000000000000000000000000000000000000000000000000626f72726f772072617465206973206162737572646c7920686967680000000023b872dd00000000000000000000000000000000000000000000000000000000544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000544f4b454e5f5452414e534645525f4f55545f4641494c45440000000000000024008a62000000000000000000000000000000000000000000000000000000008c81362d00000000000000000000000000000000000000000000000000000000c9021e2f0000000000000000000000000000000000000000000000000000000080ac7a8f0000000000000000000000000000000000000000000000000000000028ea6143000000000000000000000000000000000000000000000000000000005fc7e71e000000000000000000000000000000000000000000000000000000001429a2f20000000000000000000000000000000000000000000000000000000080965b1b000000000000000000000000000000000000000000000000000000006c540baf0000000000000000000000000000000000000000000000000000000082379c6800000000000000000000000000000000000000000000000000000000c488847b00000000000000000000000000000000000000000000000000000000414d4f554e545f5345495a455f4641494c4544000000000000000000000000004c49515549444154455f434f4d5054524f4c4c45525f43414c43554c4154455fb2a02ff100000000000000000000000000000000000000000000000000000000746f6b656e207365697a757265206661696c6564000000000000000000000000f6509350000000000000000000000000000000000000000000000000000000004c49515549444154455f5345495a455f544f4f5f4d5543480000000000000000b3058b7600000000000000000000000000000000000000000000000000000000d29da7ef000000000000000000000000000000000000000000000000000000006f46988400000000000000000000000000000000000000000000000000000000d02f735100000000000000000000000000000000000000000000000000000000c7c01c66000000000000000000000000000000000000000000000000000000007528c4ce00000000000000000000000000000000000000000000000000000000d219dc1f00000000000000000000000000000000000000000000000000000000407fded50000000000000000000000000000000000000000000000000000000017c54b9600000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0x0000000000000000000000003355df6d4c9c3035724fd0e3914de96a5a83aaf400000000000000000000000023848c28af1c3aa7b999fa57e6b6e8599c17f3f2000000000000000000000000035ed15ad908726b99bdf02001fb9715f5b99f060000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000600000000000000000000000099999a3c4cb8427c44294ad36895b6a3a047060deaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a000000000000000000000000000000000000000000000000000000000000001252656163746f72467573696f6e2055534443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067266555344430000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : underlying_ (address): 0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4
Arg [1] : comptroller_ (address): 0x23848c28Af1C3AA7B999fA57e6b6E8599C17F3f2
Arg [2] : interestRateModel_ (address): 0x035ED15Ad908726B99BDf02001fB9715f5B99F06
Arg [3] : initialExchangeRateMantissa_ (uint256): 1000000000000000000
Arg [4] : name_ (string): ReactorFusion USDC
Arg [5] : symbol_ (string): rfUSDC
Arg [6] : decimals_ (uint8): 6
Arg [7] : admin_ (address): 0x99999A3C4cB8427c44294Ad36895b6a3A047060d
Arg [8] : pythId_ (bytes32): 0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a
-----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.