Contract
0xe206074595d33bd315aa436f3eb5159668ec8f8b
1
Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
USDCmovrSOLARwell
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { 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 v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @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 ReentrancyGuard { // 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; constructor() { _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() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount ) external returns (bool); /** * @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); }
// 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/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.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)); } } /** * @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 v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 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: AGPL-3.0-only pragma solidity >=0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @notice Minimal interface for Vault compatible strategies. /// @dev Designed for out of the box compatibility with Fuse cTokens. /// @dev Like cTokens, strategies must be transferrable ERC20s. abstract contract Strategy { /// @notice Returns whether the strategy accepts ETH or an ERC20. /// @return True if the strategy accepts ETH, false otherwise. /// @dev Only present in Fuse cTokens, not Compound cTokens. function isCEther() external view virtual returns (bool); /// @notice Withdraws a specific amount of underlying tokens from the strategy. /// @param amount The amount of underlying tokens to withdraw. /// @return An error code, or 0 if the withdrawal was successful. function redeemUnderlying(uint256 amount) external virtual returns (uint256); /// @notice Returns a user's strategy balance in underlying tokens. /// @param user The user to get the underlying balance of. /// @return The user's strategy balance in underlying tokens. /// @dev May mutate the state of the strategy by accruing interest. function balanceOfUnderlying(address user) external virtual returns (uint256); /// @notice Returns max deposits a strategy can take. /// @return MaxTvl function getMaxTvl() external virtual returns (uint256); /// @notice Withdraws any ERC20 tokens back to recipient. function emergencyWithdraw(address recipient, IERC20[] memory tokens) external virtual; } /// @notice Minimal interface for Vault strategies that accept ERC20s. /// @dev Designed for out of the box compatibility with Fuse cERC20s. abstract contract ERC20Strategy is Strategy { /// @notice Returns the underlying ERC20 token the strategy accepts. /// @return The underlying ERC20 token the strategy accepts. function underlying() external view virtual returns (IERC20); /// @notice Deposit a specific amount of underlying tokens into the strategy. /// @param amount The amount of underlying tokens to deposit. /// @return An error code, or 0 if the deposit was successful. function mint(uint256 amount) external virtual returns (uint256); } /// @notice Minimal interface for Vault strategies that accept ETH. /// @dev Designed for out of the box compatibility with Fuse cEther. abstract contract ETHStrategy is Strategy { /// @notice Deposit a specific amount of ETH into the strategy. /// @dev The amount of ETH is specified via msg.value. Reverts on error. function mint() external payable virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IComptroller.sol"; import "./InterestRateModel.sol"; interface ICTokenStorage { /** * @dev 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 { uint256 principal; uint256 interestIndex; } } interface ICToken is ICTokenStorage { /*** Market Events ***/ /** * @dev Event emitted when interest is accrued */ event AccrueInterest( uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows ); /** * @dev Event emitted when tokens are minted */ event Mint(address minter, uint256 mintAmount, uint256 mintTokens); /** * @dev Event emitted when tokens are redeemed */ event Redeem(address redeemer, uint256 redeemAmount, uint256 redeemTokens); /** * @dev Event emitted when underlying is borrowed */ event Borrow( address borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows ); /** * @dev Event emitted when a borrow is repaid */ event RepayBorrow( address payer, address borrower, uint256 repayAmount, uint256 accountBorrows, uint256 totalBorrows ); /** * @dev Event emitted when a borrow is liquidated */ event LiquidateBorrow( address liquidator, address borrower, uint256 repayAmount, address cTokenCollateral, uint256 seizeTokens ); /*** Admin Events ***/ /** * @dev Event emitted when pendingAdmin is changed */ event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); /** * @dev Event emitted when pendingAdmin is accepted, which means admin is updated */ event NewAdmin(address oldAdmin, address newAdmin); /** * @dev Event emitted when comptroller is changed */ event NewComptroller(IComptroller oldComptroller, IComptroller newComptroller); /** * @dev Event emitted when interestRateModel is changed */ event NewMarketInterestRateModel( InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel ); /** * @dev Event emitted when the reserve factor is changed */ event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa); /** * @dev Event emitted when the reserves are added */ event ReservesAdded(address benefactor, uint256 addAmount, uint256 newTotalReserves); /** * @dev Event emitted when the reserves are reduced */ event ReservesReduced(address admin, uint256 reduceAmount, uint256 newTotalReserves); /** * @dev EIP20 Transfer event */ event Transfer(address indexed from, address indexed to, uint256 amount); /** * @dev EIP20 Approval event */ event Approval(address indexed owner, address indexed spender, uint256 amount); /** * @dev Failure event */ event Failure(uint256 error, uint256 info, uint256 detail); /*** User Interface ***/ function totalBorrows() external view returns (uint256); function totalReserves() external view returns (uint256); function totalSupply() external view returns (uint256); function transfer(address dst, uint256 amount) external returns (bool); function transferFrom( address src, address dst, uint256 amount ) external returns (bool); function approve(address spender, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function balanceOfUnderlying(address owner) external returns (uint256); function getAccountSnapshot(address account) external view returns ( uint256, uint256, uint256, uint256 ); function borrowRatePerBlock() external view returns (uint256); function supplyRatePerBlock() external view returns (uint256); function totalBorrowsCurrent() external returns (uint256); function borrowBalanceCurrent(address account) external returns (uint256); function borrowBalanceStored(address account) external view returns (uint256); function exchangeRateCurrent() external returns (uint256); function exchangeRateStored() external view returns (uint256); function getCash() external view returns (uint256); function accrueInterest() external returns (uint256); function seize( address liquidator, address borrower, uint256 seizeTokens ) external returns (uint256); /*** Admin Functions ***/ function _setPendingAdmin(address payable newPendingAdmin) external returns (uint256); function _acceptAdmin() external returns (uint256); function _setComptroller(IComptroller newComptroller) external returns (uint256); function _setReserveFactor(uint256 newReserveFactorMantissa) external returns (uint256); function _reduceReserves(uint256 reduceAmount) external returns (uint256); function _setInterestRateModel(InterestRateModel newInterestRateModel) external returns (uint256); } interface ICTokenErc20 is ICToken { /*** User Interface ***/ function mint(uint256 mintAmount) external returns (uint256); function redeem(uint256 redeemTokens) external returns (uint256); function redeemUnderlying(uint256 redeemAmount) external returns (uint256); function borrow(uint256 borrowAmount) external returns (uint256); function repayBorrow(uint256 repayAmount) external returns (uint256); function liquidateBorrow( address borrower, uint256 repayAmount, ICToken cTokenCollateral ) external returns (uint256); /*** Admin Functions ***/ function _addReserves(uint256 addAmount) external returns (uint256); } interface ICTokenBase is ICToken { function repayBorrow() external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./ICTokenInterfaces.sol"; interface ICompPriceOracle { function isPriceOracle() external view returns (bool); /** * @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(address cToken) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./ICTokenInterfaces.sol"; interface IComptroller { /*** Assets You Are In ***/ function enterMarkets(address[] calldata cTokens) external returns (uint256[] memory); function exitMarket(address cToken) external returns (uint256); /*** Policy Hooks ***/ function mintAllowed( address cToken, address minter, uint256 mintAmount ) external returns (uint256); function mintVerify( address cToken, address minter, uint256 mintAmount, uint256 mintTokens ) external; function redeemAllowed( address cToken, address redeemer, uint256 redeemTokens ) external returns (uint256); function redeemVerify( address cToken, address redeemer, uint256 redeemAmount, uint256 redeemTokens ) external; function borrowAllowed( address cToken, address borrower, uint256 borrowAmount ) external returns (uint256); function borrowVerify( address cToken, address borrower, uint256 borrowAmount ) external; function repayBorrowAllowed( address cToken, address payer, address borrower, uint256 repayAmount ) external returns (uint256); function repayBorrowVerify( address cToken, address payer, address borrower, uint256 repayAmount, uint256 borrowerIndex ) external; function liquidateBorrowAllowed( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint256 repayAmount ) external returns (uint256); function liquidateBorrowVerify( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint256 repayAmount, uint256 seizeTokens ) external; function seizeAllowed( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens ) external returns (uint256); function seizeVerify( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens ) external; function transferAllowed( address cToken, address src, address dst, uint256 transferTokens ) external returns (uint256); function transferVerify( address cToken, address src, address dst, uint256 transferTokens ) external; function claimComp(address holder) external; function claimComp(address holder, ICTokenErc20[] memory cTokens) external; /*** Liquidity/Liquidation Calculations ***/ function liquidateCalculateSeizeTokens( address cTokenBorrowed, address cTokenCollateral, uint256 repayAmount ) external view returns (uint256, uint256); } interface UnitrollerAdminStorage { /** * @notice Administrator for this contract */ // address external admin; function admin() external view returns (address); /** * @notice Pending administrator for this contract */ // address external pendingAdmin; function pendingAdmin() external view returns (address); /** * @notice Active brains of Unitroller */ // address external comptrollerImplementation; function comptrollerImplementation() external view returns (address); /** * @notice Pending brains of Unitroller */ // address external pendingComptrollerImplementation; function pendingComptrollerImplementation() external view returns (address); } interface ComptrollerV1Storage is UnitrollerAdminStorage { /** * @notice Oracle which gives the price of any given asset */ // PriceOracle external oracle; function oracle() external view returns (address); /** * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow */ // uint external closeFactorMantissa; function closeFactorMantissa() external view returns (uint256); /** * @notice Multiplier representing the discount on collateral that a liquidator receives */ // uint external liquidationIncentiveMantissa; function liquidationIncentiveMantissa() external view returns (uint256); /** * @notice Max number of assets a single account can participate in (borrow or use as collateral) */ // uint external maxAssets; function maxAssets() external view returns (uint256); /** * @notice Per-account mapping of "assets you are in", capped by maxAssets */ // mapping(address => CToken[]) external accountAssets; // function accountAssets(address) external view returns (CToken[]); } abstract contract ComptrollerV2Storage is ComptrollerV1Storage { enum Version { VANILLA, COLLATERALCAP, WRAPPEDNATIVE } struct Market { bool isListed; uint256 collateralFactorMantissa; mapping(address => bool) accountMembership; bool isComped; // Version version; } /** * @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 external pauseGuardian; // bool external _mintGuardianPaused; // bool external _borrowGuardianPaused; // bool external transferGuardianPaused; // bool external seizeGuardianPaused; // mapping(address => bool) external mintGuardianPaused; // mapping(address => bool) external borrowGuardianPaused; } abstract contract ComptrollerV3Storage is ComptrollerV2Storage { // struct CompMarketState { // /// @notice The market's last updated compBorrowIndex or compSupplyIndex // uint224 index; // /// @notice The block number the index was last updated at // uint32 block; // } // /// @notice A list of all markets // CToken[] external allMarkets; // /// @notice The rate at which the flywheel distributes COMP, per block // uint external compRate; // /// @notice The portion of compRate that each market currently receives // mapping(address => uint) external compSpeeds; // /// @notice The COMP market supply state for each market // mapping(address => CompMarketState) external compSupplyState; // /// @notice The COMP market borrow state for each market // mapping(address => CompMarketState) external compBorrowState; // /// @notice The COMP borrow index for each market for each supplier as of the last time they accrued COMP // mapping(address => mapping(address => uint)) external compSupplierIndex; // /// @notice The COMP borrow index for each market for each borrower as of the last time they accrued COMP // mapping(address => mapping(address => uint)) external compBorrowerIndex; // /// @notice The COMP accrued but not yet transferred to each user // mapping(address => uint) external compAccrued; } abstract 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 external borrowCapGuardian; function borrowCapGuardian() external view virtual returns (address); // @notice Borrow caps enforced by borrowAllowed for each cToken address. Defaults to zero which corresponds to unlimited borrowing. // mapping(address => uint) external borrowCaps; function borrowCaps(address) external view virtual returns (uint256); } abstract contract ComptrollerV5Storage is ComptrollerV4Storage { // @notice The supplyCapGuardian can set supplyCaps to any number for any market. Lowering the supply cap could disable supplying to the given market. // address external supplyCapGuardian; function supplyCapGuardian() external view virtual returns (address); // @notice Supply caps enforced by mintAllowed for each cToken address. Defaults to zero which corresponds to unlimited supplying. // mapping(address => uint) external supplyCaps; function supplyCaps(address) external view virtual returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Compound's InterestRateModel Interface * @author Compound */ interface InterestRateModel { /** * @dev 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 amnount of reserves the market has * @return The borrow rate per block (as a percentage, and scaled by 1e18) */ function getBorrowRate( uint256 cash, uint256 borrows, uint256 reserves ) external view returns (uint256); /** * @dev 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 amnount 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( uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract IClaimReward { function claimReward(uint8 rewardType, address payable holder) external virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IStakingRewards is IERC20 { function stakingToken() external view returns (address); function lastTimeRewardApplicable() external view returns (uint256); function rewardPerToken() external view returns (uint256); function earned(address account) external view returns (uint256); function getRewardForDuration() external view returns (uint256); function stakeWithPermit( uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function stake(uint256 amount) external; function withdraw(uint256 amount) external; function getReward() external; function exit() external; } // some farms use sushi interface interface IMasterChef { // depositing 0 amount will withdraw the rewards (harvest) function deposit(uint256 _pid, uint256 _amount) external; function withdraw(uint256 _pid, uint256 _amount) external; function userInfo(uint256 _pid, address _user) external view returns (uint256, uint256); function emergencyWithdraw(uint256 _pid) external; function pendingTokens(uint256 _pid, address _user) external view returns ( uint256, address, string memory, uint256 ); } interface IMiniChefV2 { struct UserInfo { uint256 amount; int256 rewardDebt; } struct PoolInfo { uint128 accSushiPerShare; uint64 lastRewardTime; uint64 allocPoint; } function poolLength() external view returns (uint256); function updatePool(uint256 pid) external returns (IMiniChefV2.PoolInfo memory); function userInfo(uint256 _pid, address _user) external view returns (uint256, int256); function deposit( uint256 pid, uint256 amount, address to ) external; function withdraw( uint256 pid, uint256 amount, address to ) external; function harvest(uint256 pid, address to) external; function withdrawAndHarvest( uint256 pid, uint256 amount, address to ) external; function emergencyWithdraw(uint256 pid, address to) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint256); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 value ) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns ( uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ); function price0CumulativeLast() external view returns (uint256); function price1CumulativeLast() external view returns (uint256); function kLast() external view returns (uint256); function mint(address to) external returns (uint256 liquidity); function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns ( uint256 amountA, uint256 amountB, uint256 liquidity ); function addLiquidityETH( address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable returns ( uint256 amountToken, uint256 amountETH, uint256 liquidity ); function removeLiquidity( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETH( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETHWithPermit( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountToken, uint256 amountETH); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactETHForTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function swapTokensForExactETH( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapETHForExactTokens( uint256 amountOut, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) external pure returns (uint256 amountB); function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountOut); function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountIn); function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts); function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; function balanceOf(address) external returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; library SafeETH { function safeTransferETH(address to, uint256 amount) internal { bool callStatus; assembly { // Transfer the ETH and store if it succeeded or not. callStatus := call(gas(), to, amount, 0, 0, 0, 0) } require(callStatus, "ETH_TRANSFER_FAILED"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interfaces/uniswap/IUniswapV2Pair.sol"; import "../interfaces/uniswap/IUniswapV2Router01.sol"; import "../interfaces/uniswap/IUniswapV2Factory.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; library UniUtils { using SafeERC20 for IERC20; function _getPairTokens(IUniswapV2Pair pair) internal view returns (address, address) { return (pair.token0(), pair.token1()); } function _getPairReserves( IUniswapV2Pair pair, address tokenA, address tokenB ) internal view returns (uint256 reserveA, uint256 reserveB) { (address token0, ) = _sortTokens(tokenA, tokenB); (uint256 reserve0, uint256 reserve1, ) = pair.getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // given some amount of an asset and lp reserves, returns an equivalent amount of the other asset function _quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) internal pure returns (uint256 amountB) { require(amountA > 0, "UniUtils: INSUFFICIENT_AMOUNT"); require(reserveA > 0 && reserveB > 0, "UniUtils: INSUFFICIENT_LIQUIDITY"); amountB = (amountA * reserveB) / reserveA; } function _sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "UniUtils: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "UniUtils: ZERO_ADDRESS"); } function _getAmountOut( IUniswapV2Pair pair, uint256 amountIn, address inToken, address outToken ) internal view returns (uint256 amountOut) { require(amountIn > 0, "UniUtils: INSUFFICIENT_INPUT_AMOUNT"); (uint256 reserveIn, uint256 reserveOut) = _getPairReserves(pair, inToken, outToken); uint256 amountInWithFee = amountIn * 997; uint256 numerator = amountInWithFee * reserveOut; uint256 denominator = reserveIn * 1000 + amountInWithFee; amountOut = numerator / denominator; } function _getAmountIn( IUniswapV2Pair pair, uint256 amountOut, address inToken, address outToken ) internal view returns (uint256 amountIn) { require(amountOut > 0, "UniUtils: INSUFFICIENT_OUTPUT_AMOUNT"); (uint256 reserveIn, uint256 reserveOut) = _getPairReserves(pair, inToken, outToken); uint256 numerator = reserveIn * amountOut * 1000; uint256 denominator = (reserveOut - amountOut) * 997; amountIn = (numerator / denominator) + 1; } function _swapExactTokensForTokens( IUniswapV2Pair pair, uint256 amountIn, address inToken, address outToken ) internal returns (uint256) { uint256 amountOut = _getAmountOut(pair, amountIn, inToken, outToken); (address token0, ) = _sortTokens(outToken, inToken); (uint256 amount0Out, uint256 amount1Out) = inToken == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0)); IERC20(inToken).safeTransfer(address(pair), amountIn); pair.swap(amount0Out, amount1Out, address(this), new bytes(0)); return amountOut; } function _swapTokensForExactTokens( IUniswapV2Pair pair, uint256 amountOut, address inToken, address outToken ) internal returns (uint256) { uint256 amountIn = _getAmountIn(pair, amountOut, inToken, outToken); (address token0, ) = _sortTokens(outToken, inToken); (uint256 amount0Out, uint256 amount1Out) = inToken == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0)); IERC20(inToken).safeTransfer(address(pair), amountIn); pair.swap(amount0Out, amount1Out, address(this), new bytes(0)); return amountIn; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; struct Config { address underlying; address short; address cTokenLend; address cTokenBorrow; address uniPair; address uniFarm; address farmToken; uint256 farmId; address farmRouter; address comptroller; address lendRewardRouter; address lendRewardToken; address vault; string symbol; string name; uint256 maxTvl; } // all interfaces need to inherit from base abstract contract IBase { bool public isIntialized; modifier initializer() { require(isIntialized == false, "INITIALIZED"); _; } function short() public view virtual returns (IERC20); function underlying() public view virtual returns (IERC20); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interfaces/compound/ICTokenInterfaces.sol"; import "../interfaces/compound/IComptroller.sol"; import "../interfaces/compound/ICompPriceOracle.sol"; import "../interfaces/compound/IComptroller.sol"; import "../interfaces/uniswap/IWETH.sol"; import "./ILending.sol"; import "./IBase.sol"; // import "hardhat/console.sol"; abstract contract ICompound is ILending { using SafeERC20 for IERC20; function cTokenLend() public view virtual returns (ICTokenErc20); function cTokenBorrow() public view virtual returns (ICTokenErc20); function oracle() public view virtual returns (ICompPriceOracle); function comptroller() public view virtual returns (IComptroller); function _enterMarket() internal { address[] memory cTokens = new address[](2); cTokens[0] = address(cTokenLend()); cTokens[1] = address(cTokenBorrow()); comptroller().enterMarkets(cTokens); } function _getCollateralFactor() internal view override returns (uint256) { (, uint256 collateralFactorMantissa, ) = ComptrollerV2Storage(address(comptroller())) .markets(address(cTokenLend())); return collateralFactorMantissa; } // TODO handle error function _redeem(uint256 amount) internal override { uint256 err = cTokenLend().redeemUnderlying(amount); // require(err == 0, "Compund: error redeeming underlying"); } function _borrow(uint256 amount) internal override { cTokenBorrow().borrow(amount); // in case we need to wrap the tokens if (_isBase(1)) IWETH(address(short())).deposit{ value: amount }(); } function _lend(uint256 amount) internal override { cTokenLend().mint(amount); } function _repay(uint256 amount) internal override { if (_isBase(1)) { // need to convert to base first IWETH(address(short())).withdraw(amount); // then repay in the base _repayBase(amount); return; } cTokenBorrow().repayBorrow(amount); } function _repayBase(uint256 amount) internal { ICTokenBase(address(cTokenBorrow())).repayBorrow{ value: amount }(); } function _updateAndGetCollateralBalance() internal override returns (uint256) { return cTokenLend().balanceOfUnderlying(address(this)); } function _getCollateralBalance() internal view override returns (uint256) { uint256 b = cTokenLend().balanceOf(address(this)); return (b * cTokenLend().exchangeRateStored()) / 1e18; } function _updateAndGetBorrowBalance() internal override returns (uint256) { return cTokenBorrow().borrowBalanceCurrent(address(this)); } function _getBorrowBalance() internal view override returns (uint256 shortBorrow) { shortBorrow = cTokenBorrow().borrowBalanceStored(address(this)); } function _oraclePriceOfShort(uint256 amount) internal view override returns (uint256) { return (amount * oracle().getUnderlyingPrice(address(cTokenBorrow()))) / oracle().getUnderlyingPrice(address(cTokenLend())); } function _oraclePriceOfUnderlying(uint256 amount) internal view override returns (uint256) { return (amount * oracle().getUnderlyingPrice(address(cTokenLend()))) / oracle().getUnderlyingPrice(address(cTokenBorrow())); } function _maxBorrow() internal view virtual override returns (uint256) { return cTokenBorrow().getCash(); } // returns true if either of the CTokens is cEth // index 0 = cTokenLend index 1 = cTokenBorrow function _isBase(uint8 index) internal virtual returns (bool) {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interfaces/uniswap/IUniswapV2Router01.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./IBase.sol"; struct HarvestSwapParms { address[] path; //path that the token takes uint256 min; // min price of in token * 1e18 (computed externally based on spot * slippage + fees) uint256 deadline; } abstract contract IFarmable is IBase { using SafeERC20 for IERC20; event HarvestedToken(address indexed token, uint256 amount); function _swap( IUniswapV2Router01 router, HarvestSwapParms calldata swapParams, address from, uint256 amount ) internal { address out = swapParams.path[swapParams.path.length - 1]; // ensure malicious harvester is not trading with wrong tokens // TODO should we limit path length to 2 to prevent malicious path? require( ((swapParams.path[0] == address(from) && (out == address(short()))) || out == address(underlying())), "IFarmable: WRONG_PATH" ); router.swapExactTokensForTokens( amount, swapParams.min, swapParams.path, // optimal route determined externally address(this), swapParams.deadline ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; import "./IFarmable.sol"; abstract contract IFarmableLp is IFarmable { function _depositIntoFarm(uint256 amount) internal virtual; function _withdrawFromFarm(uint256 amount) internal virtual; function _harvestFarm(HarvestSwapParms[] calldata swapParams) internal virtual returns (uint256[] memory); function _getFarmLp() internal view virtual returns (uint256); function _addFarmApprovals() internal virtual; function farmRouter() public view virtual returns (IUniswapV2Router01); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IBase.sol"; import "./IFarmable.sol"; // import "hardhat/console.sol"; abstract contract ILending is IBase { function _addLendingApprovals() internal virtual; function _getCollateralBalance() internal view virtual returns (uint256); function _getBorrowBalance() internal view virtual returns (uint256); function _updateAndGetCollateralBalance() internal virtual returns (uint256); function _updateAndGetBorrowBalance() internal virtual returns (uint256); function _getCollateralFactor() internal view virtual returns (uint256); function safeCollateralRatio() public view virtual returns (uint256); function _oraclePriceOfShort(uint256 amount) internal view virtual returns (uint256); function _oraclePriceOfUnderlying(uint256 amount) internal view virtual returns (uint256); function _lend(uint256 amount) internal virtual; function _redeem(uint256 amount) internal virtual; function _borrow(uint256 amount) internal virtual; function _repay(uint256 amount) internal virtual; function _harvestLending(HarvestSwapParms[] calldata swapParams) internal virtual returns (uint256[] memory); function lendFarmRouter() public view virtual returns (IUniswapV2Router01); function getCollateralRatio() public view virtual returns (uint256) { return (_getCollateralFactor() * safeCollateralRatio()) / 1e18; } // returns loan health value which is collateralBalance / minCollateral function loanHealth() public view returns (uint256) { uint256 borrowValue = _oraclePriceOfShort(_getBorrowBalance()); if (borrowValue == 0) return 10000; uint256 collateralBalance = _getCollateralBalance(); uint256 minCollateral = (borrowValue * 1e18) / _getCollateralFactor(); return (1e18 * collateralBalance) / minCollateral; } function _adjustCollateral(uint256 targetCollateral) internal returns (uint256 added, uint256 removed) { uint256 collateralBalance = _getCollateralBalance(); if (collateralBalance == targetCollateral) return (0, 0); (added, removed) = collateralBalance > targetCollateral ? (uint256(0), _removeCollateral(collateralBalance - targetCollateral)) : (_addCollateral(targetCollateral - collateralBalance), uint256(0)); } function _removeCollateral(uint256 amountToRemove) internal returns (uint256 removed) { uint256 maxRemove = _freeCollateral(); removed = maxRemove > amountToRemove ? amountToRemove : maxRemove; if (removed > 0) _redeem(removed); } function _freeCollateral() internal view returns (uint256) { uint256 collateral = _getCollateralBalance(); uint256 borrowValue = _oraclePriceOfShort(_getBorrowBalance()); // stay within 1% of the liquidation threshold (this is allways temporary) uint256 minCollateral = (100 * (borrowValue * 1e18)) / _getCollateralFactor() / 99; if (minCollateral > collateral) return 0; return collateral - minCollateral; } function _addCollateral(uint256 amountToAdd) internal returns (uint256 added) { uint256 underlyingBalance = underlying().balanceOf(address(this)); added = underlyingBalance > amountToAdd ? amountToAdd : underlyingBalance; if (added != 0) _lend(added); } function _maxBorrow() internal view virtual returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract ILp { function _quote( uint256 amount, address token0, address token1 ) internal view virtual returns (uint256 price); function _addLiquidity(uint256 amountToken0, uint256 amountToken1) internal virtual returns (uint256 liquidity); function _removeLiquidity(uint256 liquidity) internal virtual returns (uint256, uint256); function _getLPBalances() internal view virtual returns (uint256 underlyingBalance, uint256 shortBalance); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../interfaces/uniswap/IUniswapV2Pair.sol"; import "../libraries/UniUtils.sol"; import "./IBase.sol"; import "./ILp.sol"; // import "hardhat/console.sol"; abstract contract IUniLp is IBase, ILp { using SafeERC20 for IERC20; using UniUtils for IUniswapV2Pair; function pair() public view virtual returns (IUniswapV2Pair); function _getLiquidity() internal view virtual returns (uint256); // should only be called after oracle or user-input swap price check function _addLiquidity(uint256 amountToken0, uint256 amountToken1) internal override returns (uint256 liquidity) { underlying().safeTransfer(address(pair()), amountToken0); short().safeTransfer(address(pair()), amountToken1); liquidity = pair().mint(address(this)); } function _removeLiquidity(uint256 liquidity) internal override returns (uint256, uint256) { IERC20(address(pair())).safeTransfer(address(pair()), liquidity); (address tokenA, ) = UniUtils._sortTokens(address(underlying()), address(short())); (uint256 amountToken0, uint256 amountToken1) = pair().burn(address(this)); return tokenA == address(underlying()) ? (amountToken0, amountToken1) : (amountToken1, amountToken0); } function _quote( uint256 amount, address token0, address token1 ) internal view virtual override returns (uint256 price) { if (amount == 0) return 0; (uint256 reserve0, uint256 reserve1) = pair()._getPairReserves(token0, token1); price = UniUtils._quote(amount, reserve0, reserve1); } // fetches and sorts the reserves for a uniswap pair function getUnderlyingShortReserves() public view returns (uint256 reserveA, uint256 reserveB) { (reserveA, reserveB) = pair()._getPairReserves(address(underlying()), address(short())); } function _getLPBalances() internal view override returns (uint256 underlyingBalance, uint256 shortBalance) { uint256 totalLp = _getLiquidity(); (uint256 totalUnderlyingBalance, uint256 totalShortBalance) = getUnderlyingShortReserves(); uint256 total = pair().totalSupply(); underlyingBalance = (totalUnderlyingBalance * totalLp) / total; shortBalance = (totalShortBalance * totalLp) / total; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../interfaces/Strategy.sol"; import "../libraries/SafeETH.sol"; // import "hardhat/console.sol"; abstract contract BaseStrategy is Strategy, Ownable, ReentrancyGuard { using SafeERC20 for IERC20; modifier onlyVault() { require(msg.sender == vault(), "Strat: ONLY_VAULT"); _; } modifier onlyAuth() { require(msg.sender == owner() || _managers[msg.sender] == true, "Strat: NO_AUTH"); _; } bool isInitialized; uint256 constant BPS_ADJUST = 10000; uint256 public lastHarvest; // block.timestamp; address private _vault; uint256 private _shares; string public name; string public symbol; mapping(address => bool) private _managers; uint256 public BASE_UNIT; // 10 ** decimals event Harvest(uint256 harvested); // this is actual the tvl before harvest event Deposit(address sender, uint256 amount); event Withdraw(address sender, uint256 amount); event Rebalance(uint256 shortPrice, uint256 tvlBeforeRebalance, uint256 positionOffset); event EmergencyWithdraw(address indexed recipient, IERC20[] tokens); event ManagerUpdate(address indexed account, bool isManager); event VaultUpdate(address indexed vault); constructor( address vault_, string memory symbol_, string memory name_ ) Ownable() ReentrancyGuard() { _vault = vault_; symbol = symbol_; name = name_; } // VIEW function vault() public view returns (address) { return _vault; } function totalSupply() public view returns (uint256) { return _shares; } /** * @notice * Returns the share price of the strategy in `underlying` units, multiplied * by 1e18 */ function getPricePerShare() public view returns (uint256) { uint256 bal = balanceOfUnderlying(); if (_shares == 0) return BASE_UNIT; return (bal * BASE_UNIT) / _shares; } function balanceOfUnderlying(address) public view virtual override returns (uint256) { return balanceOfUnderlying(); } function balanceOfUnderlying() public view virtual returns (uint256); // PUBLIC METHODS function mint(uint256 amount) external onlyVault returns (uint256 errCode) { uint256 newShares = _deposit(amount); _shares += newShares; errCode = 0; } function redeemUnderlying(uint256 amount) external override onlyVault returns (uint256 errCode) { uint256 burnShares = _withdraw(amount); _shares -= burnShares; errCode = 0; } // GOVERNANCE - MANAGER function isManager(address user) public view returns (bool) { return _managers[user]; } function setManager(address user, bool _isManager) external onlyOwner { _managers[user] = _isManager; emit ManagerUpdate(user, _isManager); } function setVault(address vault_) external onlyOwner { _vault = vault_; emit VaultUpdate(vault_); } // emergency only // closePosition should be attempted first, if after some tokens are stuck, // send them to a designated address function emergencyWithdraw(address recipient, IERC20[] calldata tokens) external override onlyVault { for (uint256 i = 0; i < tokens.length; i++) { IERC20 token = tokens[i]; uint256 balance = token.balanceOf(address(this)); if (balance != 0) token.safeTransfer(recipient, balance); } if (address(this).balance > 0) SafeETH.safeTransferETH(msg.sender, address(this).balance); emit EmergencyWithdraw(recipient, tokens); } function _deposit(uint256 amount) internal virtual returns (uint256 newShares); function _withdraw(uint256 amount) internal virtual returns (uint256 burnShares); function isCEther() public pure override returns (bool) { return false; } receive() external payable {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "../mixins/IBase.sol"; import "../mixins/ILending.sol"; import "../mixins/IFarmableLp.sol"; import "../mixins/IUniLp.sol"; import "./BaseStrategy.sol"; import "../interfaces/uniswap/IWETH.sol"; // import "hardhat/console.sol"; // @custom: alphabetize dependencies to avoid linearization conflicts abstract contract HedgedLP is IBase, BaseStrategy, ILending, IFarmableLp, IUniLp { using UniUtils for IUniswapV2Pair; using SafeERC20 for IERC20; event RebalanceLoan(address indexed sender, uint256 startLoanHealth, uint256 updatedLoanHealth); event setMinLoanHealth(uint256 loanHealth); event SetMaxPriceMismatch(uint256 loanHealth); event SetRebalanceThreshold(uint256 loanHealth); event SetMaxTvl(uint256 loanHealth); event SetSafeCollateralRaio(uint256 collateralRatio); uint256 constant MINIMUM_LIQUIDITY = 1000; IERC20 private _underlying; IERC20 private _short; uint256 public maxPriceMismatch = 150; // 1.5% uint256 constant maxAllowedMismatch = 300; // manager cannot make price mismatch more than 3% uint256 public minLoanHealth = 1.04e18; // how close to liquidation we get uint16 public rebalanceThreshold = 400; // 4% of lp uint256 private _maxTvl; uint256 private _safeCollateralRatio = 8400; // 84% (90% is possible but not safe) // for security we update this value only after oracle price checks in 'getAndUpdateTvl' uint256 private _cachedBalanceOfUnderlying; uint256 public constant version = 1; modifier checkPrice(uint256 maxSlippage) { if (maxSlippage == 0) maxSlippage = maxPriceMismatch; require(getPriceOffset() <= maxSlippage, "HLP: PRICE_MISMATCH"); _; // any method that uses checkPrice should updated the _cachedBalanceOfUnderlying (_cachedBalanceOfUnderlying, , , , , ) = getTVL(); } function __HedgedLP_init_( address underlying_, address short_, uint256 maxTvl_ ) internal initializer { _underlying = IERC20(underlying_); _short = IERC20(short_); _underlying.safeApprove(address(this), type(uint256).max); BASE_UNIT = 10**decimals(); // init params setMaxTvl(maxTvl_); // emit default settings events emit setMinLoanHealth(minLoanHealth); emit SetMaxPriceMismatch(maxPriceMismatch); emit SetRebalanceThreshold(rebalanceThreshold); emit SetSafeCollateralRaio(_safeCollateralRatio); // TODO should we add a revoke aprovals methods? _addLendingApprovals(); _addFarmApprovals(); isInitialized = true; } function safeCollateralRatio() public view override returns (uint256) { return _safeCollateralRatio; } function setSafeCollateralRatio(uint256 safeCollateralRatio_) public onlyOwner { _safeCollateralRatio = safeCollateralRatio_; emit SetSafeCollateralRaio(safeCollateralRatio_); } function decimals() public view returns (uint8) { return IERC20Metadata(address(_underlying)).decimals(); } // OWNER CONFIG function setMinLoanHeath(uint256 minLoanHealth_) public onlyOwner { minLoanHealth = minLoanHealth_; emit setMinLoanHealth(minLoanHealth_); } // manager can adjust max price if needed function setMaxPriceMismatch(uint256 maxPriceMismatch_) public onlyAuth { require(msg.sender == owner() || maxAllowedMismatch >= maxPriceMismatch_, "HLP: TOO LARGE"); maxPriceMismatch = maxPriceMismatch_; emit SetMaxPriceMismatch(maxPriceMismatch_); } function setRebalanceThreshold(uint16 rebalanceThreshold_) public onlyOwner { rebalanceThreshold = rebalanceThreshold_; emit SetRebalanceThreshold(rebalanceThreshold_); } function setMaxTvl(uint256 maxTvl_) public onlyAuth { _maxTvl = maxTvl_; emit SetMaxTvl(maxTvl_); } // PUBLIC METHODS function short() public view override returns (IERC20) { return _short; } function underlying() public view override returns (IERC20) { return _underlying; } // public method that anyone can call to prevent an immenent loan liquidation // this is an emergency measure in case rebalance() is not called in time // price check is not necessary here because we are only removing LP and // if swap price differs it is to our benefit function rebalanceLoan() public nonReentrant { uint256 _loanHealth = loanHealth(); require(_loanHealth <= minLoanHealth, "HLP: SAFE"); (uint256 underlyingLp, ) = _getLPBalances(); // remove 5% of LP to repay loan & add collateral uint256 newLP = (9500 * _loanHealth * underlyingLp) / 10000 / minLoanHealth; // remove lp (uint256 underlyingBalance, uint256 shortBalance) = _decreaseLpTo(newLP); _repay(shortBalance); _lend(underlyingBalance); emit RebalanceLoan(msg.sender, _loanHealth, loanHealth()); } function _deposit(uint256 amount) internal override checkPrice(0) nonReentrant returns (uint256 newShares) { if (amount <= 0) return 0; // cannot deposit 0 uint256 tvl = _getAndUpdateTVL(); require(amount + tvl <= getMaxTvl(), "HLP: OVER_MAX_TVL"); newShares = totalSupply() == 0 ? amount : (totalSupply() * amount) / tvl; _underlying.transferFrom(vault(), address(this), amount); _increasePosition(amount); emit Deposit(msg.sender, amount); } // can pass type(uint256).max to withdraw full amount function _withdraw(uint256 amount) internal override checkPrice(0) nonReentrant returns (uint256 burnShares) { if (amount == 0) return 0; uint256 tvl = _getAndUpdateTVL(); if (tvl == 0) return 0; uint256 reserves = _underlying.balanceOf(address(this)); // if we can not withdraw straight out of reserves if (reserves < amount) { // add .5% to withdraw amount for tx fees & slippage etc uint256 withdrawAmnt = amount == type(uint256).max ? tvl : min(tvl, (amount * 1005) / 1000); // decrease current position withdrawAmnt = withdrawAmnt >= tvl ? _closePosition() : _decreasePosition(withdrawAmnt - reserves) + reserves; // use the minimum of the two amount = min(withdrawAmnt, amount); } // grab current tvl to account for fees and slippage (tvl, , , , , ) = getTVL(); // round up to keep price precision and leave less dust burnShares = min(((amount + 1) * totalSupply()) / tvl, totalSupply()); _underlying.safeTransferFrom(address(this), vault(), amount); // require(tvl > 0, "no funds in vault"); emit Withdraw(msg.sender, amount); } // decreases position based on current desired balance // ** does not rebalance remaining portfolio // ** may return slighly less then desired amount // ** make sure to update lending positions before calling this function _decreasePosition(uint256 amount) internal returns (uint256) { uint256 removeLpAmnt = _totalToLp(amount); (uint256 underlyingLp, ) = _getLPBalances(); uint256 shortPosition = _getBorrowBalance(); uint256 removeShortLp = _underlyingToShort(removeLpAmnt); if (removeLpAmnt >= underlyingLp || removeShortLp >= shortPosition) return _closePosition(); // remove lp (uint256 availableUnderlying, uint256 shortBalance) = _decreaseLpTo( underlyingLp - removeLpAmnt ); _repay(shortBalance); // this might remove less collateral than desired if we hit the limit // this happens when position is close to empty availableUnderlying += _removeCollateral(amount - availableUnderlying); return availableUnderlying; } // increases the position based on current desired balance // ** does not rebalance remaining portfolio function _increasePosition(uint256 amount) internal { if (amount < MINIMUM_LIQUIDITY) return; // avoid imprecision uint256 amntUnderlying = _totalToLp(amount); uint256 amntShort = _underlyingToShort(amntUnderlying); _lend(amount - amntUnderlying); _borrow(amntShort); uint256 liquidity = _addLiquidity(amntUnderlying, amntShort); _depositIntoFarm(liquidity); } // use the return of the function to estimate pending harvest via staticCall function harvest( HarvestSwapParms[] calldata uniParams, HarvestSwapParms[] calldata lendingParams ) external onlyAuth checkPrice(0) nonReentrant returns (uint256[] memory farmHarvest, uint256[] memory lendHarvest) { (uint256 startTvl, , , , , ) = getTVL(); if (uniParams.length != 0) farmHarvest = _harvestFarm(uniParams); if (lendingParams.length != 0) lendHarvest = _harvestLending(lendingParams); // compound our lp position disreguarding the borrowTarget param _increaseLpPosition(type(uint256).max); emit Harvest(startTvl); } // MANAGER + OWNER METHODS // Backwards compatability function rebalance() external pure { require(false, "MUST_USE_SLIPPAGE"); } function rebalance(uint256 maxSlippage) external onlyAuth checkPrice(maxSlippage) nonReentrant { // call this first to ensure we use an updated borrowBalance when computing offset uint256 tvl = _getAndUpdateTVL(); uint256 positionOffset = getPositionOffset(); // don't rebalance unless we exceeded the threshold require(positionOffset > rebalanceThreshold, "HLP: REB-THRESH"); // maybe next time... if (tvl == 0) return; uint256 targetUnderlyingLP = _totalToLp(tvl); // add .1% room for fees _rebalancePosition((targetUnderlyingLP * 999) / 1000, tvl - targetUnderlyingLP); emit Rebalance(_shortToUnderlying(1e18), positionOffset, tvl); } function closePosition(uint256 maxSlippage) public checkPrice(maxSlippage) onlyAuth { _closePosition(); } function _closePosition() internal returns (uint256) { _decreaseLpTo(0); uint256 shortPosition = _updateAndGetBorrowBalance(); uint256 shortBalance = _short.balanceOf(address(this)); if (shortPosition > shortBalance) { pair()._swapTokensForExactTokens( shortPosition - shortBalance, address(_underlying), address(_short) ); } else if (shortBalance > shortPosition) { pair()._swapExactTokensForTokens( shortBalance - shortPosition, address(_short), address(_underlying) ); } _repay(_short.balanceOf(address(this))); uint256 collateralBalance = _updateAndGetCollateralBalance(); _redeem(collateralBalance); return _underlying.balanceOf(address(this)); } function _decreaseLpTo(uint256 targetUnderlyingLP) internal returns (uint256 underlyingRemove, uint256 shortRemove) { (uint256 underlyingLp, ) = _getLPBalances(); if (targetUnderlyingLP >= underlyingLp) return (0, 0); // nothing to withdraw uint256 liquidity = _getLiquidity(); uint256 targetLiquidity = (liquidity * targetUnderlyingLP) / underlyingLp; uint256 removeLp = liquidity - targetLiquidity; uint256 liquidityBalance = pair().balanceOf(address(this)); if (removeLp > liquidityBalance) _withdrawFromFarm(removeLp - liquidityBalance); return removeLp == 0 ? (0, 0) : _removeLiquidity(removeLp); } function _rebalancePosition(uint256 targetUnderlyingLP, uint256 targetCollateral) internal { uint256 targetBorrow = _underlyingToShort(targetUnderlyingLP); // we already updated tvl uint256 currentBorrow = _getBorrowBalance(); // borrow funds or repay loan if (targetBorrow > currentBorrow) { // remove extra lp (we may need to remove more in order to add more collateral) _decreaseLpTo( _needUnderlying(targetUnderlyingLP, targetCollateral) > 0 ? 0 : targetUnderlyingLP ); // add collateral _adjustCollateral(targetCollateral); _borrow(targetBorrow - currentBorrow); } else if (targetBorrow < currentBorrow) { // remove all of lp so we can repay loan _decreaseLpTo(0); uint256 repayAmnt = min(_short.balanceOf(address(this)), currentBorrow - targetBorrow); if (repayAmnt > 0) _repay(repayAmnt); // remove extra collateral _adjustCollateral(targetCollateral); } _increaseLpPosition(targetBorrow); } /////////////////////////// //// INCREASE LP POSITION /////////////////////// function _increaseLpPosition(uint256 targetBorrow) internal { uint256 underlyingBalance = _underlying.balanceOf(address(this)); uint256 shortBalance = _short.balanceOf(address(this)); // here we make sure we don't add extra lp (, uint256 shortLP) = _getLPBalances(); if (targetBorrow < shortLP) return; uint256 addShort = min( (shortBalance + _underlyingToShort(underlyingBalance)) / 2, targetBorrow - shortLP ); uint256 addUnderlying = _shortToUnderlying(addShort); // buy or sell underlying if (addUnderlying < underlyingBalance) { shortBalance += pair()._swapExactTokensForTokens( underlyingBalance - addUnderlying, address(_underlying), address(_short) ); underlyingBalance = addUnderlying; } else if (shortBalance > addShort) { // swap extra tokens back (this may end up using more gas) underlyingBalance += pair()._swapExactTokensForTokens( shortBalance - addShort, address(_short), address(_underlying) ); shortBalance = addShort; } // compute final lp amounts uint256 amntShort = shortBalance; uint256 amntUnderlying = _shortToUnderlying(amntShort); if (underlyingBalance < amntUnderlying) { amntUnderlying = underlyingBalance; amntShort = _underlyingToShort(amntUnderlying); } if (amntUnderlying == 0) return; // add liquidity // don't need to use min with underlying and short because we did oracle check // amounts are exact because we used swap price above uint256 liquidity = _addLiquidity(amntUnderlying, amntShort); _depositIntoFarm(liquidity); } function _needUnderlying(uint256 tragetUnderlying, uint256 targetCollateral) internal view returns (uint256) { uint256 collateralBalance = _getCollateralBalance(); if (targetCollateral < collateralBalance) return 0; (uint256 underlyingLp, ) = _getLPBalances(); uint256 uBalance = tragetUnderlying > underlyingLp ? tragetUnderlying - underlyingLp : 0; uint256 addCollateral = targetCollateral - collateralBalance; if (uBalance >= addCollateral) return 0; return addCollateral - uBalance; } // TVL function getMaxTvl() public view override returns (uint256) { return min(_maxTvl, _borrowToTotal(_oraclePriceOfShort(_maxBorrow()))); } // TODO should we compute pending farm & lending rewards here? function _getAndUpdateTVL() internal returns (uint256 tvl) { uint256 collateralBalance = _updateAndGetCollateralBalance(); uint256 shortPosition = _updateAndGetBorrowBalance(); uint256 borrowBalance = _shortToUnderlying(shortPosition); uint256 shortP = _short.balanceOf(address(this)); uint256 shortBalance = shortP == 0 ? 0 : _shortToUnderlying(shortP); (uint256 underlyingLp, ) = _getLPBalances(); uint256 underlyingBalance = _underlying.balanceOf(address(this)); tvl = collateralBalance + underlyingLp * 2 - borrowBalance + underlyingBalance + shortBalance; } // for security this method should return cached value only // this is used by vault to track balance, // so this value should only be updated after oracle price check function balanceOfUnderlying() public view override returns (uint256) { return _cachedBalanceOfUnderlying; } function getTotalTVL() public view returns (uint256 tvl) { (tvl, , , , , ) = getTVL(); } function getTVL() public view returns ( uint256 tvl, uint256 collateralBalance, uint256 borrowPosition, uint256 borrowBalance, uint256 lpBalance, uint256 underlyingBalance ) { collateralBalance = _getCollateralBalance(); borrowPosition = _getBorrowBalance(); borrowBalance = _shortToUnderlying(borrowPosition); uint256 shortPosition = _short.balanceOf(address(this)); uint256 shortBalance = shortPosition == 0 ? 0 : _shortToUnderlying(shortPosition); (uint256 underlyingLp, uint256 shortLp) = _getLPBalances(); lpBalance = underlyingLp + _shortToUnderlying(shortLp); underlyingBalance = _underlying.balanceOf(address(this)); tvl = collateralBalance + lpBalance - borrowBalance + underlyingBalance + shortBalance; } function getPositionOffset() public view returns (uint256 positionOffset) { (, uint256 shortLp) = _getLPBalances(); uint256 borrowBalance = _getBorrowBalance(); uint256 shortBalance = shortLp + _short.balanceOf(address(this)); if (shortBalance == borrowBalance) return 0; // if short lp > 0 and borrowBalance is 0 we are off by inf, returning 100% should be enough if (borrowBalance == 0) return 10000; // this is the % by which our position has moved from beeing balanced positionOffset = shortBalance > borrowBalance ? ((shortBalance - borrowBalance) * BPS_ADJUST) / borrowBalance : ((borrowBalance - shortBalance) * BPS_ADJUST) / borrowBalance; } function getPriceOffset() public view returns (uint256 offset) { uint256 minPrice = _shortToUnderlying(1e18); uint256 maxPrice = _oraclePriceOfShort(1e18); (minPrice, maxPrice) = maxPrice > minPrice ? (minPrice, maxPrice) : (maxPrice, minPrice); offset = ((maxPrice - minPrice) * BPS_ADJUST) / maxPrice; } // UTILS function _totalToLp(uint256 total) internal view returns (uint256) { uint256 cRatio = getCollateralRatio(); return (total * cRatio) / (BPS_ADJUST + cRatio); } function _borrowToTotal(uint256 amount) internal view returns (uint256) { uint256 cRatio = getCollateralRatio(); return (amount * (BPS_ADJUST + cRatio)) / cRatio; } // this is the current uniswap price function _shortToUnderlying(uint256 amount) internal view returns (uint256) { return amount == 0 ? 0 : _quote(amount, address(_short), address(_underlying)); } // this is the current uniswap price function _underlyingToShort(uint256 amount) internal view returns (uint256) { return amount == 0 ? 0 : _quote(amount, address(_underlying), address(_short)); } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../../interfaces/forks/IClaimReward.sol"; import "./CompoundFarm.sol"; // import "hardhat/console.sol"; abstract contract CompMultiFarm is CompoundFarm { // BenQi has two two token rewards // pid 0 is Qi token and pid 1 is AVAX (not wrapped) function _harvestLending(HarvestSwapParms[] calldata swapParams) internal override returns (uint256[] memory harvested) { // farm token on id 0 IClaimReward(address(comptroller())).claimReward(0, payable(address(this))); harvested = new uint256[](1); harvested[0] = _farmToken.balanceOf(address(this)); if (harvested[0] > 0) { _swap(lendFarmRouter(), swapParams[0], address(_farmToken), harvested[0]); emit HarvestedToken(address(_farmToken), harvested[0]); } // base token rewards on id 1 IClaimReward(address(comptroller())).claimReward(1, payable(address(this))); uint256 avaxBalance = address(this).balance; if (avaxBalance > 0) { IWETH(address(short())).deposit{ value: avaxBalance }(); emit HarvestedToken(address(short()), avaxBalance); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../../interfaces/compound/ICTokenInterfaces.sol"; import "../../interfaces/compound/IComptroller.sol"; import "../../interfaces/compound/ICompPriceOracle.sol"; import "../../interfaces/compound/IComptroller.sol"; import "../../mixins/ICompound.sol"; // import "hardhat/console.sol"; abstract contract Compound is ICompound { using SafeERC20 for IERC20; ICTokenErc20 private _cTokenLend; ICTokenErc20 private _cTokenBorrow; IComptroller private _comptroller; ICompPriceOracle private _oracle; function __Compound_init_( address comptroller_, address cTokenLend_, address cTokenBorrow_ ) internal { _cTokenLend = ICTokenErc20(cTokenLend_); _cTokenBorrow = ICTokenErc20(cTokenBorrow_); _comptroller = IComptroller(comptroller_); _oracle = ICompPriceOracle(ComptrollerV1Storage(comptroller_).oracle()); _enterMarket(); } function _addLendingApprovals() internal override { // ensure USDC approval - assume we trust USDC underlying().safeApprove(address(_cTokenLend), type(uint256).max); short().safeApprove(address(_cTokenBorrow), type(uint256).max); } function cTokenLend() public view override returns (ICTokenErc20) { return _cTokenLend; } function cTokenBorrow() public view override returns (ICTokenErc20) { return _cTokenBorrow; } function oracle() public view override returns (ICompPriceOracle) { return _oracle; } function comptroller() public view override returns (IComptroller) { return _comptroller; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../../mixins/ICompound.sol"; import "../../mixins/IFarmable.sol"; import "../../interfaces/uniswap/IUniswapV2Pair.sol"; // import "hardhat/console.sol"; abstract contract CompoundFarm is ICompound, IFarmable { using SafeERC20 for IERC20; IUniswapV2Router01 private _router; // use router here IERC20 _farmToken; function __CompoundFarm_init_(address router_, address token_) internal initializer { _farmToken = IERC20(token_); _router = IUniswapV2Router01(router_); _farmToken.safeApprove(address(_router), type(uint256).max); } function lendFarmRouter() public view override returns (IUniswapV2Router01) { return _router; } function _harvestLending(HarvestSwapParms[] calldata swapParams) internal virtual override returns (uint256[] memory harvested) { // comp token rewards ICTokenErc20[] memory cTokens = new ICTokenErc20[](2); cTokens[0] = cTokenLend(); cTokens[1] = cTokenBorrow(); comptroller().claimComp(address(this), cTokens); harvested = new uint256[](1); harvested[0] = _farmToken.balanceOf(address(this)); if (harvested[0] == 0) return harvested; if (address(_router) != address(0)) _swap(_router, swapParams[0], address(_farmToken), harvested[0]); emit HarvestedToken(address(_farmToken), harvested[0]); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IMasterChef } from "../../interfaces/uniswap/IStakingRewards.sol"; import "../../interfaces/uniswap/IUniswapV2Pair.sol"; import "../../mixins/IFarmableLp.sol"; import "../../mixins/IUniLp.sol"; import "../../interfaces/uniswap/IWETH.sol"; // import "hardhat/console.sol"; abstract contract MasterChefFarm is IFarmableLp, IUniLp { using SafeERC20 for IERC20; IMasterChef private _farm; IUniswapV2Router01 private _router; IERC20 private _farmToken; IUniswapV2Pair private _pair; uint256 private _farmId; function __MasterChefFarm_init_( address pair_, address farm_, address router_, address farmToken_, uint256 farmPid_ ) internal initializer { _farm = IMasterChef(farm_); _router = IUniswapV2Router01(router_); _farmToken = IERC20(farmToken_); _pair = IUniswapV2Pair(pair_); _farmId = farmPid_; } // assumption that _router and _farm are trusted function _addFarmApprovals() internal override { IERC20(address(_pair)).safeApprove(address(_farm), type(uint256).max); if (_farmToken.allowance(address(this), address(_router)) == 0) _farmToken.safeApprove(address(_router), type(uint256).max); } function farmRouter() public view override returns (IUniswapV2Router01) { return _router; } function pair() public view override returns (IUniswapV2Pair) { return _pair; } function _withdrawFromFarm(uint256 amount) internal override { _farm.withdraw(_farmId, amount); } function _depositIntoFarm(uint256 amount) internal override { _farm.deposit(_farmId, amount); } function _harvestFarm(HarvestSwapParms[] calldata swapParams) internal override returns (uint256[] memory harvested) { _farm.deposit(_farmId, 0); harvested = new uint256[](1); harvested[0] = _farmToken.balanceOf(address(this)); if (harvested[0] == 0) return harvested; _swap(_router, swapParams[0], address(_farmToken), harvested[0]); emit HarvestedToken(address(_farmToken), harvested[0]); uint256 avaxBalance = address(this).balance; if (avaxBalance > 0) { IWETH(address(short())).deposit{ value: avaxBalance }(); emit HarvestedToken(address(short()), avaxBalance); } } function _getFarmLp() internal view override returns (uint256) { (uint256 lp, ) = _farm.userInfo(_farmId, address(this)); return lp; } function _getLiquidity() internal view override returns (uint256) { uint256 farmLp = _getFarmLp(); uint256 poolLp = _pair.balanceOf(address(this)); return farmLp + poolLp; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../HedgedLP.sol"; import "../adapters/Compound.sol"; import "../adapters/MasterChefFarm.sol"; import "../adapters/CompMultiFarm.sol"; // import "hardhat/console.sol"; contract USDCmovrSOLARwell is HedgedLP, Compound, CompMultiFarm, MasterChefFarm { // HedgedLP should allways be intialized last constructor(Config memory config) BaseStrategy(config.vault, config.symbol, config.name) { __MasterChefFarm_init_( config.uniPair, config.uniFarm, config.farmRouter, config.farmToken, config.farmId ); __Compound_init_(config.comptroller, config.cTokenLend, config.cTokenBorrow); __CompoundFarm_init_(config.lendRewardRouter, config.lendRewardToken); __HedgedLP_init_(config.underlying, config.short, config.maxTvl); } // if borrow token is treated as ETH function _isBase(uint8) internal pure override(ICompound) returns (bool) { return true; } }
{ "evmVersion": "london", "libraries": { "src/strategies/implementations/USDCmovrSOLARwell.sol:USDCmovrSOLARwell": { "UniUtils": "0x92dBEa6fa85A1cd839b604D1F2852ABfb7Fa2897" } }, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
[{"inputs":[{"components":[{"internalType":"address","name":"underlying","type":"address"},{"internalType":"address","name":"short","type":"address"},{"internalType":"address","name":"cTokenLend","type":"address"},{"internalType":"address","name":"cTokenBorrow","type":"address"},{"internalType":"address","name":"uniPair","type":"address"},{"internalType":"address","name":"uniFarm","type":"address"},{"internalType":"address","name":"farmToken","type":"address"},{"internalType":"uint256","name":"farmId","type":"uint256"},{"internalType":"address","name":"farmRouter","type":"address"},{"internalType":"address","name":"comptroller","type":"address"},{"internalType":"address","name":"lendRewardRouter","type":"address"},{"internalType":"address","name":"lendRewardToken","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"maxTvl","type":"uint256"}],"internalType":"struct Config","name":"config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"harvested","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"HarvestedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"isManager","type":"bool"}],"name":"ManagerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shortPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tvlBeforeRebalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionOffset","type":"uint256"}],"name":"Rebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"startLoanHealth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedLoanHealth","type":"uint256"}],"name":"RebalanceLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"SetMaxPriceMismatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"SetMaxTvl","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"SetRebalanceThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateralRatio","type":"uint256"}],"name":"SetSafeCollateralRaio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"VaultUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanHealth","type":"uint256"}],"name":"setMinLoanHealth","type":"event"},{"inputs":[],"name":"BASE_UNIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cTokenBorrow","outputs":[{"internalType":"contract ICTokenErc20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cTokenLend","outputs":[{"internalType":"contract ICTokenErc20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxSlippage","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract IComptroller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"farmRouter","outputs":[{"internalType":"contract IUniswapV2Router01","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCollateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxTvl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPositionOffset","outputs":[{"internalType":"uint256","name":"positionOffset","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPriceOffset","outputs":[{"internalType":"uint256","name":"offset","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTVL","outputs":[{"internalType":"uint256","name":"tvl","type":"uint256"},{"internalType":"uint256","name":"collateralBalance","type":"uint256"},{"internalType":"uint256","name":"borrowPosition","type":"uint256"},{"internalType":"uint256","name":"borrowBalance","type":"uint256"},{"internalType":"uint256","name":"lpBalance","type":"uint256"},{"internalType":"uint256","name":"underlyingBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalTVL","outputs":[{"internalType":"uint256","name":"tvl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingShortReserves","outputs":[{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct HarvestSwapParms[]","name":"uniParams","type":"tuple[]"},{"components":[{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct HarvestSwapParms[]","name":"lendingParams","type":"tuple[]"}],"name":"harvest","outputs":[{"internalType":"uint256[]","name":"farmHarvest","type":"uint256[]"},{"internalType":"uint256[]","name":"lendHarvest","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCEther","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"isIntialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastHarvest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lendFarmRouter","outputs":[{"internalType":"contract IUniswapV2Router01","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loanHealth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPriceMismatch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLoanHealth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"errCode","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract ICompPriceOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxSlippage","type":"uint256"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalanceLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalanceThreshold","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"errCode","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"safeCollateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"_isManager","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxPriceMismatch_","type":"uint256"}],"name":"setMaxPriceMismatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxTvl_","type":"uint256"}],"name":"setMaxTvl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minLoanHealth_","type":"uint256"}],"name":"setMinLoanHeath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"rebalanceThreshold_","type":"uint16"}],"name":"setRebalanceThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"safeCollateralRatio_","type":"uint256"}],"name":"setSafeCollateralRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"short","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040526096600c55670e6ed27d66680000600d55600e805461ffff19166101901790556120d06010553480156200003757600080fd5b506040516200604f3803806200604f8339810160408190526200005a9162000e03565b6101808101516101a08201516101c0830151620000773362000147565b60018055600480546001600160a01b0319166001600160a01b0385161790558151620000ab90600790602085019062000c24565b508051620000c190600690602084019062000c24565b505050608082015160a083015161010084015160c085015160e0860151620000ea955062000197565b6200010a816101200151826040015183606001516200021c60201b60201c565b62000126816101400151826101600151620002e860201b60201c565b805160208201516101e0830151620001409291906200035d565b5062001330565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60025460ff1615620001c65760405162461bcd60e51b8152600401620001bd9062000fa5565b60405180910390fd5b601880546001600160a01b03199081166001600160a01b039687161790915560198054821694861694909417909355601a8054841692851692909217909155601b80549092169390921692909217909155601c55565b601280546001600160a01b038085166001600160a01b03199283161790925560138054848416908316179055601480549286169290911682179055604080516307dc0d1d60e41b81529051637dc0d1d0916004808201926020929091908290030181865afa15801562000293573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b9919062000fca565b601580546001600160a01b0319166001600160a01b0392909216919091179055620002e36200050b565b505050565b60025460ff16156200030e5760405162461bcd60e51b8152600401620001bd9062000fa5565b601780546001600160a01b03199081166001600160a01b0384811691821790935560168054909216928516928317909155620003599160001962000607602090811b62001a3317901c565b5050565b60025460ff1615620003835760405162461bcd60e51b8152600401620001bd9062000fa5565b600a80546001600160a01b038086166001600160a01b03199283168117909355600b805491861691909216179055620003cf903060001962001a3362000607602090811b91909117901c565b620003d962000752565b620003e690600a620010fd565b600955620003f481620007c8565b7f5ceaf8b7b0d35f85ef4df565057cd318e70d9f8681f89425a2d5e09c1c70a7f9600d546040516200042891815260200190565b60405180910390a17f3e87fa3180c1babd204ce79375729d7a6694a2d2f0fb3e250f9138488ed066bb600c546040516200046491815260200190565b60405180910390a1600e5460405161ffff90911681527f36c98a54ec4f90fe58a67bf25cfc1691dbd53639eee3513536d83e8d34fb0a9b9060200160405180910390a17f4812bd1abd1ad4ea905335e3af941ec67d6d51ecb36ab58f23af0af081aac57b601054604051620004db91815260200190565b60405180910390a1620004ed62000870565b620004f7620008de565b50506002805461ff00191661010017905550565b6040805160028082526060820183526000926020830190803683375050601254919250506001600160a01b0316816000815181106200054e576200054e6200110e565b6001600160a01b03928316602091820292909201015260135416816001815181106200057e576200057e6200110e565b6001600160a01b039283166020918202929092010152601454604051631853304760e31b815291169063c299823890620005bd90849060040162001124565b6000604051808303816000875af1158015620005dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000359919081019062001173565b801580620006865750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e9062000640903090869060040162001223565b602060405180830381865afa1580156200065e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200068491906200123d565b155b620006fa5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401620001bd565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620002e3918591620009ba16565b600a546040805163313ce56760e01b815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa1580156200079d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007c3919062001257565b905090565b6000546001600160a01b0316331480620007f657503360009081526008602052604090205460ff1615156001145b620008355760405162461bcd60e51b815260206004820152600e60248201526d0a6e8e4c2e874409c9ebe82aaa8960931b6044820152606401620001bd565b600f8190556040518181527f13d3e08a22782064d3062f92ff1101a623b60e3bf91f236b5d1e9fdddfc12a129060200160405180910390a150565b601254620008b5906001600160a01b031660001962000897600a546001600160a01b031690565b6001600160a01b03166200060760201b62001a33179092919060201c565b601354620008dc906001600160a01b031660001962000897600b546001600160a01b031690565b565b601854601b546200090b916001600160a01b03918216911660001962000607602090811b62001a3317901c565b601a54601954604051636eb1769f60e11b81526001600160a01b039283169263dd62ed3e92620009449230929091169060040162001223565b602060405180830381865afa15801562000962573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200098891906200123d565b620008dc57601954601a54620008dc916001600160a01b03918216911660001962000607602090811b62001a3317901c565b600062000a16826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662000a9860201b62001b73179092919060201c565b805190915015620002e3578080602001905181019062000a3791906200127c565b620002e35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620001bd565b606062000aa9848460008562000ab3565b90505b9392505050565b60608247101562000b165760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620001bd565b843b62000b665760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001bd565b600080866001600160a01b0316858760405162000b849190620012a0565b60006040518083038185875af1925050503d806000811462000bc3576040519150601f19603f3d011682016040523d82523d6000602084013e62000bc8565b606091505b50909250905062000bdb82828662000be6565b979650505050505050565b6060831562000bf757508162000aac565b82511562000c085782518084602001fd5b8160405162461bcd60e51b8152600401620001bd9190620012be565b82805462000c3290620012f3565b90600052602060002090601f01602090048101928262000c56576000855562000ca1565b82601f1062000c7157805160ff191683800117855562000ca1565b8280016001018555821562000ca1579182015b8281111562000ca157825182559160200191906001019062000c84565b5062000caf92915062000cb3565b5090565b5b8082111562000caf576000815560010162000cb4565b634e487b7160e01b600052604160045260246000fd5b60405161020081016001600160401b038111828210171562000d065762000d0662000cca565b60405290565b604051601f8201601f191681016001600160401b038111828210171562000d375762000d3762000cca565b604052919050565b80516001600160a01b038116811462000d5757600080fd5b919050565b60005b8381101562000d7957818101518382015260200162000d5f565b8381111562000d89576000848401525b50505050565b600082601f83011262000da157600080fd5b81516001600160401b0381111562000dbd5762000dbd62000cca565b62000dd2601f8201601f191660200162000d0c565b81815284602083860101111562000de857600080fd5b62000dfb82602083016020870162000d5c565b949350505050565b60006020828403121562000e1657600080fd5b81516001600160401b038082111562000e2e57600080fd5b90830190610200828603121562000e4457600080fd5b62000e4e62000ce0565b62000e598362000d3f565b815262000e696020840162000d3f565b602082015262000e7c6040840162000d3f565b604082015262000e8f6060840162000d3f565b606082015262000ea26080840162000d3f565b608082015262000eb560a0840162000d3f565b60a082015262000ec860c0840162000d3f565b60c082015260e083015160e082015261010062000ee781850162000d3f565b9082015261012062000efb84820162000d3f565b9082015261014062000f0f84820162000d3f565b9082015261016062000f2384820162000d3f565b9082015261018062000f3784820162000d3f565b908201526101a0838101518381111562000f5057600080fd5b62000f5e8882870162000d8f565b8284015250506101c0808401518381111562000f7957600080fd5b62000f878882870162000d8f565b91830191909152506101e09283015192810192909252509392505050565b6020808252600b908201526a125392551250531256915160aa1b604082015260600190565b60006020828403121562000fdd57600080fd5b62000aac8262000d3f565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200103f57816000190482111562001023576200102362000fe8565b808516156200103157918102915b93841c939080029062001003565b509250929050565b6000826200105857506001620010f7565b816200106757506000620010f7565b81600181146200108057600281146200108b57620010ab565b6001915050620010f7565b60ff8411156200109f576200109f62000fe8565b50506001821b620010f7565b5060208310610133831016604e8410600b8410161715620010d0575081810a620010f7565b620010dc838362000ffe565b8060001904821115620010f357620010f362000fe8565b0290505b92915050565b600062000aac60ff84168362001047565b634e487b7160e01b600052603260045260246000fd5b6020808252825182820181905260009190848201906040850190845b81811015620011675783516001600160a01b03168352928401929184019160010162001140565b50909695505050505050565b600060208083850312156200118757600080fd5b82516001600160401b03808211156200119f57600080fd5b818501915085601f830112620011b457600080fd5b815181811115620011c957620011c962000cca565b8060051b9150620011dc84830162000d0c565b8181529183018401918481019088841115620011f757600080fd5b938501935b838510156200121757845182529385019390850190620011fc565b98975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6000602082840312156200125057600080fd5b5051919050565b6000602082840312156200126a57600080fd5b815160ff8116811462000aac57600080fd5b6000602082840312156200128f57600080fd5b8151801515811462000aac57600080fd5b60008251620012b481846020870162000d5c565b9190910192915050565b6020815260008251806020840152620012df81604085016020870162000d5c565b601f01601f19169190910160400192915050565b600181811c908216806200130857607f821691505b602082108114156200132a57634e487b7160e01b600052602260045260246000fd5b50919050565b614d0f80620013406000396000f3fe60806040526004361061025e5760003560e01c806306fdde031461026a5780630c021ae5146102955780630d55046c146102b85780630e962f00146102df57806314b0750b146102f55780631585e0b61461031757806318160ddd14610337578063313ce5671461034c578063358d6a041461037357806338bea4cb146103885780633af9e6691461039d5780633bf295cc146103bd5780633d68175c146103d25780633dcf1342146103e75780633dfe9f6a146104075780634880f9511461043557806354fd4d501461044a5780635fe3b5671461045f57806366be952d146104745780636817031b1461048a5780636f307dc3146104aa578063711326ce146104bf578063715018a6146104df5780637d7c2a1c146104f45780637da64483146105095780637dc0d1d0146105335780637ffe28e314610548578063852a12e31461055d57806386aceac71461057d5780638da5cb5b1461059357806395d89b41146105a857806397b3fcaa146105bd578063a0712d68146105ff578063a126d6011461061f578063a52602b91461063f578063a5e90eee14610654578063a8aa1b3114610674578063ac784ddc14610689578063b580a1281461069d578063c2946e24146106b2578063cb50087f146106c7578063cd377c53146106e7578063d539fe4b146106fc578063de747e5a14610711578063f1a392da14610731578063f20aea0f14610747578063f2fde38b14610775578063f3ae241514610795578063f4993018146107ce578063f9e40ac4146107ee578063fbfa77cf14610811578063fd6bac7014610826578063fec18b3a1461083b57600080fd5b3661026557005b600080fd5b34801561027657600080fd5b5061027f610850565b60405161028c91906144e0565b60405180910390f35b3480156102a157600080fd5b506102aa6108de565b60405190815260200161028c565b3480156102c457600080fd5b506019546001600160a01b03165b60405161028c91906144f3565b3480156102eb57600080fd5b506102aa60095481565b34801561030157600080fd5b50610315610310366004614507565b6108f3565b005b34801561032357600080fd5b50610315610332366004614507565b610967565b34801561034357600080fd5b506005546102aa565b34801561035857600080fd5b506103616109d1565b60405160ff909116815260200161028c565b34801561037f57600080fd5b506102aa610a44565b34801561039457600080fd5b506102d2610a69565b3480156103a957600080fd5b506102aa6103b8366004614535565b610a78565b3480156103c957600080fd5b506102aa610a89565b3480156103de57600080fd5b506102aa610b00565b3480156103f357600080fd5b50610315610402366004614596565b610b41565b34801561041357600080fd5b50600e546104229061ffff1681565b60405161ffff909116815260200161028c565b34801561044157600080fd5b506011546102aa565b34801561045657600080fd5b506102aa600181565b34801561046b57600080fd5b506102d2610ca8565b34801561048057600080fd5b506102aa600c5481565b34801561049657600080fd5b506103156104a5366004614535565b610cb7565b3480156104b657600080fd5b506102d2610d30565b3480156104cb57600080fd5b506103156104da366004614507565b610d3f565b3480156104eb57600080fd5b50610315610e31565b34801561050057600080fd5b50610315610e6c565b34801561051557600080fd5b506002546105239060ff1681565b604051901515815260200161028c565b34801561053f57600080fd5b506102d2610ea8565b34801561055457600080fd5b50610315610eb7565b34801561056957600080fd5b506102aa610578366004614507565b610fdb565b34801561058957600080fd5b506102aa600d5481565b34801561059f57600080fd5b506102d2611042565b3480156105b457600080fd5b5061027f611051565b3480156105c957600080fd5b506105d261105e565b604080519687526020870195909552938501929092526060840152608083015260a082015260c00161028c565b34801561060b57600080fd5b506102aa61061a366004614507565b6111e7565b34801561062b57600080fd5b5061031561063a366004614507565b611240565b34801561064b57600080fd5b506102d26112e9565b34801561066057600080fd5b5061031561066f3660046145f8565b6112f8565b34801561068057600080fd5b506102d2611386565b34801561069557600080fd5b506000610523565b3480156106a957600080fd5b506102aa611395565b3480156106be57600080fd5b506102aa611498565b3480156106d357600080fd5b506103156106e2366004614507565b611502565b3480156106f357600080fd5b506102aa61158e565b34801561070857600080fd5b506010546102aa565b34801561071d57600080fd5b5061031561072c366004614631565b6115be565b34801561073d57600080fd5b506102aa60035481565b34801561075357600080fd5b50610767610762366004614655565b611631565b60405161028c9291906146fb565b34801561078157600080fd5b50610315610790366004614535565b61177a565b3480156107a157600080fd5b506105236107b0366004614535565b6001600160a01b031660009081526008602052604090205460ff1690565b3480156107da57600080fd5b506103156107e9366004614507565b61181a565b3480156107fa57600080fd5b506108036119cf565b60405161028c929190614729565b34801561081d57600080fd5b506102d2611a06565b34801561083257600080fd5b506102d2611a15565b34801561084757600080fd5b506102d2611a24565b6006805461085d90614737565b80601f016020809104026020016040519081016040528092919081815260200182805461088990614737565b80156108d65780601f106108ab576101008083540402835291602001916108d6565b820191906000526020600020905b8154815290600101906020018083116108b957829003601f168201915b505050505081565b60006108e861105e565b509395945050505050565b336108fc611042565b6001600160a01b03161461092b5760405162461bcd60e51b81526004016109229061476c565b60405180910390fd5b60108190556040518181527f4812bd1abd1ad4ea905335e3af941ec67d6d51ecb36ab58f23af0af081aac57b906020015b60405180910390a150565b33610970611042565b6001600160a01b0316146109965760405162461bcd60e51b81526004016109229061476c565b600d8190556040518181527f5ceaf8b7b0d35f85ef4df565057cd318e70d9f8681f89425a2d5e09c1c70a7f99060200161095c565b60055490565b600a546040805163313ce56760e01b815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa158015610a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f91906147a1565b905090565b6000610a3f600f54610a64610a5f610a5a611b8c565b611bf7565b611d03565b611d31565b600b546001600160a01b031690565b6000610a8360115490565b92915050565b600080610a97610a5a611d47565b905080610aa75761271091505090565b6000610ab1611d99565b90506000610abd611e8e565b610acf84670de0b6b3a76400006147da565b610ad991906147f9565b905080610aee83670de0b6b3a76400006147da565b610af891906147f9565b935050505090565b600080610b0c60115490565b905060055460001415610b2157505060095490565b600554600954610b3190836147da565b610b3b91906147f9565b91505090565b610b49611a06565b6001600160a01b0316336001600160a01b031614610b795760405162461bcd60e51b81526004016109229061481b565b60005b81811015610c4f576000838383818110610b9857610b98614846565b9050602002016020810190610bad9190614535565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610bdd91906144f3565b602060405180830381865afa158015610bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1e919061485c565b90508015610c3a57610c3a6001600160a01b0383168783611f14565b50508080610c4790614875565b915050610b7c565b504715610c6057610c603347611f33565b826001600160a01b03167f2b06144d62a3a5785ec284ed392b3d106610ae2ce7af270417c4ca38277571048383604051610c9b929190614890565b60405180910390a2505050565b6014546001600160a01b031690565b33610cc0611042565b6001600160a01b031614610ce65760405162461bcd60e51b81526004016109229061476c565b600480546001600160a01b0319166001600160a01b0383169081179091556040517fdabed91cf547ed2ee836d5787bae42fc3bca488166c65791051105490fbcf7ca90600090a250565b600a546001600160a01b031690565b610d47611042565b6001600160a01b0316336001600160a01b03161480610d7a57503360009081526008602052604090205460ff1615156001145b610d965760405162461bcd60e51b8152600401610922906148de565b610d9e611042565b6001600160a01b0316336001600160a01b03161480610dbf57508061012c10155b610dfc5760405162461bcd60e51b815260206004820152600e60248201526d484c503a20544f4f204c4152474560901b6044820152606401610922565b600c8190556040518181527f3e87fa3180c1babd204ce79375729d7a6694a2d2f0fb3e250f9138488ed066bb9060200161095c565b33610e3a611042565b6001600160a01b031614610e605760405162461bcd60e51b81526004016109229061476c565b610e6a6000611f84565b565b60405162461bcd60e51b81526020600482015260116024820152704d5553545f5553455f534c49505041474560781b6044820152606401610922565b6015546001600160a01b031690565b60026001541415610eda5760405162461bcd60e51b815260040161092290614906565b60026001556000610ee9610a89565b9050600d54811115610f295760405162461bcd60e51b8152602060048201526009602482015268484c503a205341464560b81b6044820152606401610922565b6000610f33611fd4565b5090506000600d54612710838561251c610f4d91906147da565b610f5791906147da565b610f6191906147f9565b610f6b91906147f9565b9050600080610f7983612095565b91509150610f86816121a3565b610f8f8261225a565b337fdacd0a02d11128b25d6c3de23e91f71aa9dd5620c6f5c69f35a18d15e116846886610fba610a89565b604051610fc8929190614729565b60405180910390a2505060018055505050565b6000610fe5611a06565b6001600160a01b0316336001600160a01b0316146110155760405162461bcd60e51b81526004016109229061481b565b60006110208361228f565b90508060056000828254611034919061493d565b909155506000949350505050565b6000546001600160a01b031690565b6007805461085d90614737565b60008060008060008061106f611d99565b9450611079611d47565b9350611084846124be565b600b546040516370a0823160e01b81529194506000916001600160a01b03909116906370a08231906110ba9030906004016144f3565b602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb919061485c565b9050600081156111135761110e826124be565b611116565b60005b9050600080611123611fd4565b91509150611130816124be565b61113a9083614954565b600a546040516370a0823160e01b81529197506001600160a01b0316906370a082319061116b9030906004016144f3565b602060405180830381865afa158015611188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac919061485c565b94508285886111bb898d614954565b6111c5919061493d565b6111cf9190614954565b6111d99190614954565b995050505050909192939495565b60006111f1611a06565b6001600160a01b0316336001600160a01b0316146112215760405162461bcd60e51b81526004016109229061481b565b600061122c836124f1565b905080600560008282546110349190614954565b808061124b5750600c545b80611254611498565b11156112725760405162461bcd60e51b81526004016109229061496c565b61127a611042565b6001600160a01b0316336001600160a01b031614806112ad57503360009081526008602052604090205460ff1615156001145b6112c95760405162461bcd60e51b8152600401610922906148de565b6112d16126b0565b506112da61105e565b50505060119290925550505050565b6012546001600160a01b031690565b33611301611042565b6001600160a01b0316146113275760405162461bcd60e51b81526004016109229061476c565b6001600160a01b038216600081815260086020908152604091829020805460ff191685151590811790915591519182527f2458f684567d238b66deaa0126265bf3becabda0caaab7ebdda6b1794614a2d3910160405180910390a25050565b601b546001600160a01b031690565b6000806113a0611fd4565b91505060006113ad611d47565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906113e39030906004016144f3565b602060405180830381865afa158015611400573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611424919061485c565b61142e9084614954565b905081811415611442576000935050505090565b8161145257612710935050505090565b8181116114805781612710611467838361493d565b61147191906147da565b61147b91906147f9565b610af8565b8161271061148e828461493d565b610aee91906147da565b6000806114ac670de0b6b3a76400006124be565b905060006114c1670de0b6b3a7640000611bf7565b90508181116114d15780826114d4565b81815b9092509050806127106114e7848361493d565b6114f191906147da565b6114fb91906147f9565b9250505090565b61150a611042565b6001600160a01b0316336001600160a01b0316148061153d57503360009081526008602052604090205460ff1615156001145b6115595760405162461bcd60e51b8152600401610922906148de565b600f8190556040518181527f13d3e08a22782064d3062f92ff1101a623b60e3bf91f236b5d1e9fdddfc12a129060200161095c565b6000670de0b6b3a76400006115a260105490565b6115aa611e8e565b6115b491906147da565b610a3f91906147f9565b336115c7611042565b6001600160a01b0316146115ed5760405162461bcd60e51b81526004016109229061476c565b600e805461ffff191661ffff83169081179091556040519081527f36c98a54ec4f90fe58a67bf25cfc1691dbd53639eee3513536d83e8d34fb0a9b9060200161095c565b60608061163c611042565b6001600160a01b0316336001600160a01b0316148061166f57503360009081526008602052604090205460ff1615156001145b61168b5760405162461bcd60e51b8152600401610922906148de565b600c5480611697611498565b11156116b55760405162461bcd60e51b81526004016109229061496c565b600260015414156116d85760405162461bcd60e51b815260040161092290614906565b600260015560006116e761105e565b5093945050891592506117049150505761170188886128c9565b93505b8415611717576117148686612b72565b92505b611722600019612de0565b6040518181527f80f97f878e16410266694f134ddf012f2be424f54f8b5cafa107eccc51d00d589060200160405180910390a1506001805561176261105e565b50505060119290925550929791965090945050505050565b33611783611042565b6001600160a01b0316146117a95760405162461bcd60e51b81526004016109229061476c565b6001600160a01b03811661180e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610922565b61181781611f84565b50565b611822611042565b6001600160a01b0316336001600160a01b0316148061185557503360009081526008602052604090205460ff1615156001145b6118715760405162461bcd60e51b8152600401610922906148de565b808061187c5750600c545b80611885611498565b11156118a35760405162461bcd60e51b81526004016109229061496c565b600260015414156118c65760405162461bcd60e51b815260040161092290614906565b600260015560006118d5612fe1565b905060006118e1611395565b600e5490915061ffff16811161192b5760405162461bcd60e51b815260206004820152600f60248201526e09098a07440a48a845aa890a48aa69608b1b6044820152606401610922565b816119375750506119c3565b60006119428361315f565b905061196f6103e8611956836103e76147da565b61196091906147f9565b61196a838661493d565b613182565b7fe0b4077da7dfa5015ff10fab6a214f37acc1b23d745f30336942d17e07848c6b6119a1670de0b6b3a76400006124be565b6040805191825260208201859052810185905260600160405180910390a15050505b600180556112da61105e565b6000806119fd6119dd610d30565b6119e5610a69565b6119ed611386565b6001600160a01b031691906132ad565b90939092509050565b6004546001600160a01b031690565b6013546001600160a01b031690565b6016546001600160a01b031690565b801580611aad5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aab919061485c565b155b611b185760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610922565b611b6e8363095ea7b360e01b8484604051602401611b37929190614999565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261336d565b505050565b6060611b82848460008561343f565b90505b9392505050565b6000611b96611a15565b6001600160a01b0316633b1d21a26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f919061485c565b6000611c01610ea8565b6001600160a01b031663fc57d4df611c176112e9565b6040518263ffffffff1660e01b8152600401611c3391906144f3565b602060405180830381865afa158015611c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c74919061485c565b611c7c610ea8565b6001600160a01b031663fc57d4df611c92611a15565b6040518263ffffffff1660e01b8152600401611cae91906144f3565b602060405180830381865afa158015611ccb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cef919061485c565b611cf990846147da565b610a8391906147f9565b600080611d0e61158e565b905080611d1d81612710614954565b611d2790856147da565b611b8591906147f9565b6000818310611d405781611b85565b5090919050565b6000611d51611a15565b6001600160a01b03166395dd9193306040518263ffffffff1660e01b8152600401611d7c91906144f3565b602060405180830381865afa158015611bd3573d6000803e3d6000fd5b600080611da46112e9565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611dcf91906144f3565b602060405180830381865afa158015611dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e10919061485c565b9050670de0b6b3a7640000611e236112e9565b6001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e84919061485c565b610b3190836147da565b600080611e99610ca8565b6001600160a01b0316638e8f294b611eaf6112e9565b6040518263ffffffff1660e01b8152600401611ecb91906144f3565b606060405180830381865afa158015611ee8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0c91906149b2565b509392505050565b611b6e8363a9059cbb60e01b8484604051602401611b37929190614999565b600080600080600085875af1905080611b6e5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610922565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806000611fe1613567565b9050600080611fee6119cf565b915091506000611ffc611386565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612039573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205d919061485c565b90508061206a85856147da565b61207491906147f9565b95508061208185846147da565b61208b91906147f9565b9450505050509091565b60008060006120a2611fd4565b5090508084106120b85750600093849350915050565b60006120c2613567565b90506000826120d187846147da565b6120db91906147f9565b905060006120e9828461493d565b905060006120f5611386565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161212091906144f3565b602060405180830381865afa15801561213d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612161919061485c565b90508082111561217d5761217d612178828461493d565b6135f5565b81156121915761218c8261365d565b612195565b6000805b965096505050505050915091565b6121ab610a69565b6001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b81526004016121d891815260200190565b600060405180830381600087803b1580156121f257600080fd5b505af1158015612206573d6000803e3d6000fd5b5050505061181781613753565b6020604051808303816000875af1158015612232573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612256919061485c565b5050565b6122626112e9565b6001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040161221391815260200190565b6000600c548061229d611498565b11156122bb5760405162461bcd60e51b81526004016109229061496c565b600260015414156122de5760405162461bcd60e51b815260040161092290614906565b6002600155826122f157600091506124a0565b60006122fb612fe1565b90508061230c5760009250506124a0565b600a546040516370a0823160e01b81526000916001600160a01b0316906370a082319061233d9030906004016144f3565b602060405180830381865afa15801561235a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237e919061485c565b9050848110156123fb57600060001986146123b5576123b0836103e86123a6896103ed6147da565b610a6491906147f9565b6123b7565b825b9050828110156123e357816123d46123cf828461493d565b6137b1565b6123de9190614954565b6123eb565b6123eb6126b0565b90506123f78187611d31565b9550505b61240361105e565b50939550612442935085925061241b91506109cb9050565b612426886001614954565b61243091906147da565b61243a91906147f9565b600554611d31565b935061246430612450611a06565b600a546001600160a01b0316919088613850565b7f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243643386604051612495929190614999565b60405180910390a150505b600180556124ac61105e565b50505060119290925550919392505050565b600081156124e957600b54600a546124e49184916001600160a01b039182169116613871565b610a83565b600092915050565b6000600c54806124ff611498565b111561251d5760405162461bcd60e51b81526004016109229061496c565b600260015414156125405760405162461bcd60e51b815260040161092290614906565b60026001558261255357600091506124a0565b600061255d612fe1565b9050612567610a44565b6125718286614954565b11156125b35760405162461bcd60e51b81526020600482015260116024820152701213140e8813d5915497d3505617d51593607a1b6044820152606401610922565b600554156125df5780846125c660055490565b6125d091906147da565b6125da91906147f9565b6125e1565b835b600a549093506001600160a01b03166323b872dd6125fd611a06565b30876040518463ffffffff1660e01b815260040161261d939291906149f5565b6020604051808303816000875af115801561263c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126609190614a19565b5061266a8461389f565b7fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c338560405161269b929190614999565b60405180910390a150600180556124ac61105e565b60006126bc6000612095565b505060006126c86138f8565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906126fe9030906004016144f3565b602060405180830381865afa15801561271b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273f919061485c565b90508082111561278857612782612756828461493d565b600a54600b546001600160a01b039182169116612771611386565b6001600160a01b031692919061394c565b506127cb565b818111156127cb576127c961279d838361493d565b600b54600a546001600160a01b0391821691166127b8611386565b6001600160a01b0316929190613a2b565b505b600b546040516370a0823160e01b8152612843916001600160a01b0316906370a08231906127fd9030906004016144f3565b602060405180830381865afa15801561281a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061283e919061485c565b6121a3565b600061284d613a8c565b905061285881613ac1565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906128889030906004016144f3565b602060405180830381865afa1580156128a5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af8919061485c565b601854601c54604051631c57762b60e31b81526060926001600160a01b03169163e2bbb158916128ff9190600090600401614729565b600060405180830381600087803b15801561291957600080fd5b505af115801561292d573d6000803e3d6000fd5b506001925061293a915050565b604051908082528060200260200182016040528015612963578160200160208202803683370190505b50601a546040516370a0823160e01b81529192506001600160a01b0316906370a08231906129959030906004016144f3565b602060405180830381865afa1580156129b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d6919061485c565b816000815181106129e9576129e9614846565b60200260200101818152505080600081518110612a0857612a08614846565b602002602001015160001415612a1d57610a83565b601954612a7f906001600160a01b03168484600081612a3e57612a3e614846565b9050602002810190612a509190614a4c565b601a5484516001600160a01b03909116908590600090612a7257612a72614846565b6020026020010151613b3b565b601a5481516001600160a01b0390911690600080516020614cba833981519152908390600090612ab157612ab1614846565b6020026020010151604051612ac891815260200190565b60405180910390a2478015612b6b57612adf610a69565b6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612b1957600080fd5b505af1158015612b2d573d6000803e3d6000fd5b5050505050612b3a610a69565b6001600160a01b0316600080516020614cba83398151915282604051612b6291815260200190565b60405180910390a25b5092915050565b6060612b7c610ca8565b6001600160a01b0316630952c5636000306040518363ffffffff1660e01b8152600401612baa929190614a6c565b600060405180830381600087803b158015612bc457600080fd5b505af1158015612bd8573d6000803e3d6000fd5b5060019250612be5915050565b604051908082528060200260200182016040528015612c0e578160200160208202803683370190505b506017546040516370a0823160e01b81529192506001600160a01b0316906370a0823190612c409030906004016144f3565b602060405180830381865afa158015612c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c81919061485c565b81600081518110612c9457612c94614846565b602002602001018181525050600081600081518110612cb557612cb5614846565b60200260200101511115612d6757612d15612cce611a24565b84846000818110612ce157612ce1614846565b9050602002810190612cf39190614a4c565b60175484516001600160a01b03909116908590600090612a7257612a72614846565b60175481516001600160a01b0390911690600080516020614cba833981519152908390600090612d4757612d47614846565b6020026020010151604051612d5e91815260200190565b60405180910390a25b612d6f610ca8565b6001600160a01b0316630952c5636001306040518363ffffffff1660e01b8152600401612d9d929190614a6c565b600060405180830381600087803b158015612db757600080fd5b505af1158015612dcb573d6000803e3d6000fd5b504792505081159050612b6b57612adf610a69565b600a546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612e119030906004016144f3565b602060405180830381865afa158015612e2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e52919061485c565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a0823190612e889030906004016144f3565b602060405180830381865afa158015612ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec9919061485c565b90506000612ed5611fd4565b91505080841015612ee65750505050565b6000612f146002612ef686613ce0565b612f009086614954565b612f0a91906147f9565b610a64848861493d565b90506000612f21826124be565b905084811015612f6757612f53612f38828761493d565b600a54600b546001600160a01b0391821691166127b8611386565b612f5d9085614954565b9350809450612f8c565b81841115612f8c57612f7c61279d838661493d565b612f869086614954565b94508193505b836000612f98826124be565b905080871015612fb0575085612fad81613ce0565b91505b80612fbf575050505050505050565b6000612fcb8284613d06565b9050612fd681613da6565b505050505050505050565b600080612fec613a8c565b90506000612ff86138f8565b90506000613005826124be565b600b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a082319061303b9030906004016144f3565b602060405180830381865afa158015613058573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061307c919061485c565b9050600081156130945761308f826124be565b613097565b60005b905060006130a3611fd4565b50600a546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906130da9030906004016144f3565b602060405180830381865afa1580156130f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061311b919061485c565b905082818661312b8560026147da565b613135908b614954565b61313f919061493d565b6131499190614954565b6131539190614954565b97505050505050505090565b60008061316a61158e565b905061317881612710614954565b611d2782856147da565b600061318d83613ce0565b90506000613199611d47565b9050808211156131ea576131c560006131b28686613dd9565b116131bd5784612095565b60005b612095565b50506131d083613e4d565b506131e590506131e0828461493d565b613eaa565b61329e565b8082101561329e576131fc6000612095565b5050600b546040516370a0823160e01b8152600091613280916001600160a01b03909116906370a08231906132359030906004016144f3565b602060405180830381865afa158015613252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613276919061485c565b610a64858561493d565b9050801561329157613291816121a3565b61329a84613e4d565b5050505b6132a782612de0565b50505050565b60008060006132bc8585613f65565b509050600080876001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133249190614aa4565b506001600160701b031691506001600160701b03169150826001600160a01b0316876001600160a01b03161461335b57808261335e565b81815b90999098509650505050505050565b60006133c2826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b739092919063ffffffff16565b805190915015611b6e57808060200190518101906133e09190614a19565b611b6e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610922565b6060824710156134a05760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610922565b843b6134ee5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610922565b600080866001600160a01b0316858760405161350a9190614ae9565b60006040518083038185875af1925050503d8060008114613547576040519150601f19603f3d011682016040523d82523d6000602084013e61354c565b606091505b509150915061355c828286614048565b979650505050505050565b600080613572614081565b601b546040516370a0823160e01b81529192506000916001600160a01b03909116906370a08231906135a89030906004016144f3565b602060405180830381865afa1580156135c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e9919061485c565b90506114fb8183614954565b601854601c54604051630441a3e760e41b81526001600160a01b039092169163441a3e7091613628918590600401614729565b600060405180830381600087803b15801561364257600080fd5b505af1158015613656573d6000803e3d6000fd5b5050505050565b60008061368461366b611386565b84613674611386565b6001600160a01b03169190611f14565b600061369e613691610d30565b613699610a69565b613f65565b5090506000806136ac611386565b6001600160a01b03166389afcb44306040518263ffffffff1660e01b81526004016136d791906144f3565b60408051808303816000875af11580156136f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137199190614afb565b91509150613725610d30565b6001600160a01b0316836001600160a01b031614613744578082613747565b81815b94509450505050915091565b61375b611a15565b6001600160a01b0316634e4d9fea826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561379557600080fd5b505af11580156137a9573d6000803e3d6000fd5b505050505050565b6000806137bd8361315f565b905060006137c9611fd4565b50905060006137d6611d47565b905060006137e384613ce0565b905082841015806137f45750818110155b1561380b576138016126b0565b9695505050505050565b60008061381b6131c0878761493d565b91509150613828816121a3565b61383a613835838a61493d565b6140fc565b6138449083614954565b98975050505050505050565b6132a7846323b872dd60e01b858585604051602401611b37939291906149f5565b60008361388057506000611b85565b60008061389085856119ed611386565b9150915061380186838361412f565b6103e88110156138ac5750565b60006138b78261315f565b905060006138c482613ce0565b90506138d86138d3838561493d565b61225a565b6138e181613eaa565b60006138ed8383613d06565b90506132a781613da6565b6000613902611a15565b6001600160a01b03166317bfdfbc306040518263ffffffff1660e01b815260040161392d91906144f3565b6020604051808303816000875af1158015611bd3573d6000803e3d6000fd5b60008061395b868686866141f1565b905060006139698486613f65565b509050600080826001600160a01b0316876001600160a01b03161461399057876000613994565b6000885b90925090506139ad6001600160a01b0388168a86611f14565b6040805160008152602081019182905263022c0d9f60e01b9091526001600160a01b038a169063022c0d9f906139ec9085908590309060248101614b1f565b600060405180830381600087803b158015613a0657600080fd5b505af1158015613a1a573d6000803e3d6000fd5b50959b9a5050505050505050505050565b600080613a3a868686866142b7565b90506000613a488486613f65565b509050600080826001600160a01b0316876001600160a01b031614613a6f57836000613a73565b6000845b90925090506139ad6001600160a01b0388168a8a611f14565b6000613a966112e9565b6001600160a01b0316633af9e669306040518263ffffffff1660e01b815260040161392d91906144f3565b6000613acb6112e9565b6001600160a01b031663852a12e3836040518263ffffffff1660e01b8152600401613af891815260200190565b6020604051808303816000875af1158015613b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6e919061485c565b6000613b478480614b4c565b6001613b538780614b4c565b613b5e92915061493d565b818110613b6d57613b6d614846565b9050602002016020810190613b829190614535565b90506001600160a01b038316613b988580614b4c565b6000818110613ba957613ba9614846565b9050602002016020810190613bbe9190614535565b6001600160a01b0316148015613bec5750613bd7610a69565b6001600160a01b0316816001600160a01b0316145b80613c0f5750613bfa610d30565b6001600160a01b0316816001600160a01b0316145b613c535760405162461bcd60e51b81526020600482015260156024820152740928cc2e4dac2c4d8ca7440aea49e9c8ebea082a89605b1b6044820152606401610922565b6001600160a01b0385166338ed1739836020870135613c728880614b4c565b308a604001356040518763ffffffff1660e01b8152600401613c9996959493929190614b95565b6000604051808303816000875af1158015613cb8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526137a99190810190614c08565b600081156124e957600a54600b546124e49184916001600160a01b039182169116613871565b6000613d1c613d13611386565b84613674610d30565b613d30613d27611386565b83613674610a69565b613d38611386565b6001600160a01b0316636a627842306040518263ffffffff1660e01b8152600401613d6391906144f3565b6020604051808303816000875af1158015613d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b85919061485c565b601854601c54604051631c57762b60e31b81526001600160a01b039092169163e2bbb15891613628918590600401614729565b600080613de4611d99565b905080831015613df8576000915050610a83565b6000613e02611fd4565b5090506000818611613e15576000613e1f565b613e1f828761493d565b90506000613e2d848761493d565b9050808210613e43576000945050505050610a83565b61355c828261493d565b6000806000613e5a611d99565b905083811415613e705750600093849350915050565b838111613e9057613e89613e84828661493d565b614378565b6000613e9f565b6000613e9f613835868461493d565b909590945092505050565b613eb2611a15565b6001600160a01b031663c5ebeaec826040518263ffffffff1660e01b8152600401613edf91815260200190565b6020604051808303816000875af1158015613efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f22919061485c565b50613f2b610a69565b6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561379557600080fd5b600080826001600160a01b0316846001600160a01b03161415613fca5760405162461bcd60e51b815260206004820152601d60248201527f556e695574696c733a204944454e544943414c5f4144445245535345530000006044820152606401610922565b826001600160a01b0316846001600160a01b031610613fea578284613fed565b83835b90925090506001600160a01b0382166140415760405162461bcd60e51b8152602060048201526016602482015275556e695574696c733a205a45524f5f4144445245535360501b6044820152606401610922565b9250929050565b60608315614057575081611b85565b8251156140675782518084602001fd5b8160405162461bcd60e51b815260040161092291906144e0565b601854601c546040516393f1a40b60e01b8152600481019190915230602482015260009182916001600160a01b03909116906393f1a40b906044016040805180830381865afa1580156140d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6b9190614afb565b600080614107614411565b90508281116141165780614118565b825b915081156141295761412982613ac1565b50919050565b60008084116141805760405162461bcd60e51b815260206004820152601d60248201527f556e695574696c733a20494e53554646494349454e545f414d4f554e540000006044820152606401610922565b6000831180156141905750600082115b6141dc5760405162461bcd60e51b815260206004820181905260248201527f556e695574696c733a20494e53554646494349454e545f4c49515549444954596044820152606401610922565b826141e783866147da565b611b8291906147f9565b600080841161424e5760405162461bcd60e51b8152602060048201526024808201527f556e695574696c733a20494e53554646494349454e545f4f55545055545f414d60448201526313d5539560e21b6064820152608401610922565b60008061425c8786866132ad565b9092509050600061426d87846147da565b614279906103e86147da565b90506000614287888461493d565b614293906103e56147da565b905061429f81836147f9565b6142aa906001614954565b9998505050505050505050565b60008084116143145760405162461bcd60e51b815260206004820152602360248201527f556e695574696c733a20494e53554646494349454e545f494e5055545f414d4f60448201526215539560ea1b6064820152608401610922565b6000806143228786866132ad565b90925090506000614335876103e56147da565b9050600061434383836147da565b9050600082614354866103e86147da565b61435e9190614954565b905061436a81836147f9565b9a9950505050505050505050565b600080614383610d30565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016143ae91906144f3565b602060405180830381865afa1580156143cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143ef919061485c565b90508281116143fe5780614400565b825b91508115614129576141298261225a565b60008061441c611d99565b9050600061442b610a5a611d47565b905060006063614439611e8e565b61444b84670de0b6b3a76400006147da565b6144569060646147da565b61446091906147f9565b61446a91906147f9565b90508281111561447e576000935050505090565b610af8818461493d565b60005b838110156144a357818101518382015260200161448b565b838111156132a75750506000910152565b600081518084526144cc816020860160208601614488565b601f01601f19169290920160200192915050565b602081526000611b8560208301846144b4565b6001600160a01b0391909116815260200190565b60006020828403121561451957600080fd5b5035919050565b6001600160a01b038116811461181757600080fd5b60006020828403121561454757600080fd5b8135611b8581614520565b60008083601f84011261456457600080fd5b5081356001600160401b0381111561457b57600080fd5b6020830191508360208260051b850101111561404157600080fd5b6000806000604084860312156145ab57600080fd5b83356145b681614520565b925060208401356001600160401b038111156145d157600080fd5b6145dd86828701614552565b9497909650939450505050565b801515811461181757600080fd5b6000806040838503121561460b57600080fd5b823561461681614520565b91506020830135614626816145ea565b809150509250929050565b60006020828403121561464357600080fd5b813561ffff81168114611b8557600080fd5b6000806000806040858703121561466b57600080fd5b84356001600160401b038082111561468257600080fd5b61468e88838901614552565b909650945060208701359150808211156146a757600080fd5b506146b487828801614552565b95989497509550505050565b600081518084526020808501945080840160005b838110156146f0578151875295820195908201906001016146d4565b509495945050505050565b60408152600061470e60408301856146c0565b828103602084015261472081856146c0565b95945050505050565b918252602082015260400190565b600181811c9082168061474b57607f821691505b6020821081141561412957634e487b7160e01b600052602260045260246000fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000602082840312156147b357600080fd5b815160ff81168114611b8557600080fd5b634e487b7160e01b600052601160045260246000fd5b60008160001904831182151516156147f4576147f46147c4565b500290565b60008261481657634e487b7160e01b600052601260045260246000fd5b500490565b60208082526011908201527014dd1c985d0e8813d3931657d590555315607a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561486e57600080fd5b5051919050565b6000600019821415614889576148896147c4565b5060010190565b60208082528181018390526000908460408401835b868110156148d35782356148b881614520565b6001600160a01b0316825291830191908301906001016148a5565b509695505050505050565b6020808252600e908201526d0a6e8e4c2e874409c9ebe82aaa8960931b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008282101561494f5761494f6147c4565b500390565b60008219821115614967576149676147c4565b500190565b60208082526013908201527209098a07440a0a492868abe9a92a69a82a8869606b1b604082015260600190565b6001600160a01b03929092168252602082015260400190565b6000806000606084860312156149c757600080fd5b83516149d2816145ea565b6020850151604086015191945092506149ea816145ea565b809150509250925092565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215614a2b57600080fd5b8151611b85816145ea565b634e487b7160e01b600052604160045260246000fd5b60008235605e19833603018112614a6257600080fd5b9190910192915050565b60ff9290921682526001600160a01b0316602082015260400190565b80516001600160701b0381168114614a9f57600080fd5b919050565b600080600060608486031215614ab957600080fd5b614ac284614a88565b9250614ad060208501614a88565b9150604084015163ffffffff811681146149ea57600080fd5b60008251614a62818460208701614488565b60008060408385031215614b0e57600080fd5b505080516020909101519092909150565b84815283602082015260018060a01b038316604082015260806060820152600061380160808301846144b4565b6000808335601e19843603018112614b6357600080fd5b8301803591506001600160401b03821115614b7d57600080fd5b6020019150600581901b360382131561404157600080fd5b868152602080820187905260a0604083018190528201859052600090869060c08401835b88811015614be7578335614bcc81614520565b6001600160a01b031682529282019290820190600101614bb9565b506001600160a01b0396909616606085015250505060800152949350505050565b60006020808385031215614c1b57600080fd5b82516001600160401b0380821115614c3257600080fd5b818501915085601f830112614c4657600080fd5b815181811115614c5857614c58614a36565b8060051b604051601f19603f83011681018181108582111715614c7d57614c7d614a36565b604052918252848201925083810185019188831115614c9b57600080fd5b938501935b8285101561384457845184529385019392850192614ca056fe3efad319b6afe1e0317f51df66abdc4d7a7c8b1cfda31f03440b4ad255af7245a2646970667358221220560a575531386b8f3fdd8f8afdf2fc19f99efd2998f041e7114e3138d3f5687064736f6c634300080a00330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e3f5a90f9cb311505cd691a46596599aa1a0ad7d00000000000000000000000098878b06940ae243284ca214f92bb71a2b032b8a000000000000000000000000d0670aee3698f66e2d4daf071eb9c690d978bfa80000000000000000000000006a1a771c7826596652dadc9145feaae62b1cd07f000000000000000000000000e537f70a8b62204832b8ba91940b77d3f79aeb810000000000000000000000000329867a8c457e9f75e25b0685011291cd30904f0000000000000000000000006bd193ee6d2104f14f94e2ca6efefae561a4334b000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f0000000000000000000000000b7a0eaa884849c6af7a129e899536dddca4905e000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f000000000000000000000000bb8d88bcd9749636bc4d2be22aac4bb3b01a58f1000000000000000000000000c24d43093b44b7a9657571ddb79fedf014eaef7d00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000011555344436d6f7672534f4c415277656c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001855534443204d4f565220534f4c4152204d6f6f6e77656c6c0000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e3f5a90f9cb311505cd691a46596599aa1a0ad7d00000000000000000000000098878b06940ae243284ca214f92bb71a2b032b8a000000000000000000000000d0670aee3698f66e2d4daf071eb9c690d978bfa80000000000000000000000006a1a771c7826596652dadc9145feaae62b1cd07f000000000000000000000000e537f70a8b62204832b8ba91940b77d3f79aeb810000000000000000000000000329867a8c457e9f75e25b0685011291cd30904f0000000000000000000000006bd193ee6d2104f14f94e2ca6efefae561a4334b000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f0000000000000000000000000b7a0eaa884849c6af7a129e899536dddca4905e000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f000000000000000000000000bb8d88bcd9749636bc4d2be22aac4bb3b01a58f1000000000000000000000000c24d43093b44b7a9657571ddb79fedf014eaef7d00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000011555344436d6f7672534f4c415277656c6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001855534443204d4f565220534f4c4152204d6f6f6e77656c6c0000000000000000
-----Decoded View---------------
Arg [0] : config (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
21 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 000000000000000000000000e3f5a90f9cb311505cd691a46596599aa1a0ad7d
Arg [2] : 00000000000000000000000098878b06940ae243284ca214f92bb71a2b032b8a
Arg [3] : 000000000000000000000000d0670aee3698f66e2d4daf071eb9c690d978bfa8
Arg [4] : 0000000000000000000000006a1a771c7826596652dadc9145feaae62b1cd07f
Arg [5] : 000000000000000000000000e537f70a8b62204832b8ba91940b77d3f79aeb81
Arg [6] : 0000000000000000000000000329867a8c457e9f75e25b0685011291cd30904f
Arg [7] : 0000000000000000000000006bd193ee6d2104f14f94e2ca6efefae561a4334b
Arg [8] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [9] : 000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f
Arg [10] : 0000000000000000000000000b7a0eaa884849c6af7a129e899536dddca4905e
Arg [11] : 000000000000000000000000aa30ef758139ae4a7f798112902bf6d65612045f
Arg [12] : 000000000000000000000000bb8d88bcd9749636bc4d2be22aac4bb3b01a58f1
Arg [13] : 000000000000000000000000c24d43093b44b7a9657571ddb79fedf014eaef7d
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000240
Arg [16] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [18] : 555344436d6f7672534f4c415277656c6c000000000000000000000000000000
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [20] : 55534443204d4f565220534f4c4152204d6f6f6e77656c6c0000000000000000
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.