Source Code
Latest 5 from a total of 5 transactions
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CompoundLeverageStrategyUNI
Compiler Version
v0.8.3+commit.8d00100c
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
import "./CompoundLeverageStrategy.sol";
import "../../interfaces/token/IToken.sol";
// solhint-disable no-empty-blocks
/// @title Deposit UNI in Compound and also borrow UNI based on leverage condition
contract CompoundLeverageStrategyUNI is CompoundLeverageStrategy {
string public constant NAME = "Compound-Leverage-Strategy-UNI";
string public constant VERSION = "3.0.12";
// cUNI = 0x35A18000230DA775CAc24873d00Ff85BccdeD550
constructor(address _pool, address _swapManager)
CompoundLeverageStrategy(_pool, _swapManager, 0x35A18000230DA775CAc24873d00Ff85BccdeD550)
{}
}// SPDX-License-Identifier: MIT
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
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'
// solhint-disable-next-line max-line-length
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
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
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;
// solhint-disable-next-line no-inline-assembly
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");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(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");
// solhint-disable-next-line avoid-low-level-calls
(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");
// solhint-disable-next-line avoid-low-level-calls
(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");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
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) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/vesper/IVesperPool.sol";
import "./interfaces/aave/IAave.sol";
import "./interfaces/dydx/ISoloMargin.sol";
/**
* @title FlashLoanHelper:: This contract does all heavy lifting to get flash loan via Aave and DyDx.
* @dev End user has to override _flashLoanLogic() function to perform logic after flash loan is done.
* Also needs to approve token to aave and dydx via _approveToken function.
* 2 utility internal functions are also provided to activate/deactivate flash loan providers.
* Utility function are provided as internal so that end user can choose controlled access via public functions.
*/
abstract contract FlashLoanHelper {
using SafeERC20 for IERC20;
AaveLendingPoolAddressesProvider internal constant AAVE_ADDRESSES_PROVIDER =
AaveLendingPoolAddressesProvider(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5);
address internal constant SOLO = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
uint256 public dyDxMarketId;
bool public isAaveActive = false;
bool public isDyDxActive = false;
function _updateAaveStatus(bool _status) internal {
isAaveActive = _status;
}
function _updateDyDxStatus(bool _status, address _token) internal {
if (_status) {
dyDxMarketId = _getMarketIdFromTokenAddress(SOLO, _token);
}
isDyDxActive = _status;
}
/// @notice Approve all required tokens for flash loan
function _approveToken(address _token, uint256 _amount) internal {
IERC20(_token).safeApprove(SOLO, _amount);
IERC20(_token).safeApprove(AAVE_ADDRESSES_PROVIDER.getLendingPool(), _amount);
}
/// @dev Override this function to execute logic which uses flash loan amount
// solhint-disable-next-line no-empty-blocks
function _flashLoanLogic(bytes memory _data, uint256 _repayAmount) internal virtual {}
/***************************** Aave flash loan functions ***********************************/
bool private awaitingFlash = false;
/**
* @notice This is entry point for Aave flash loan
* @param _token Token for which we are taking flash loan
* @param _amountDesired Flash loan amount
* @param _data This will be passed downstream for processing. It can be empty.
*/
function _doAaveFlashLoan(
address _token,
uint256 _amountDesired,
bytes memory _data
) internal returns (uint256 _amount) {
require(isAaveActive, "aave-flash-loan-is-not-active");
AaveLendingPool _aaveLendingPool = AaveLendingPool(AAVE_ADDRESSES_PROVIDER.getLendingPool());
address[] memory assets = new address[](1);
assets[0] = _token;
uint256[] memory amounts = new uint256[](1);
amounts[0] = _amountDesired;
// 0 = no debt, 1 = stable, 2 = variable
uint256[] memory modes = new uint256[](1);
modes[0] = 0;
// Anyone can call aave flash loan to us, so we need some protection
awaitingFlash = true;
// function params: receiver, assets, amounts, modes, onBehalfOf, data, referralCode
_aaveLendingPool.flashLoan(address(this), assets, amounts, modes, address(this), _data, 0);
_amount = _amountDesired;
awaitingFlash = false;
}
/// @dev Aave will call this function after doing flash loan
function executeOperation(
address[] calldata, /*_assets*/
uint256[] calldata _amounts,
uint256[] calldata _premiums,
address _initiator,
bytes calldata _data
) external returns (bool) {
require(msg.sender == AAVE_ADDRESSES_PROVIDER.getLendingPool(), "!aave-pool");
require(awaitingFlash, "invalid-flash-loan");
require(_initiator == address(this), "invalid-initiator");
// Flash loan amount + flash loan fee
uint256 _repayAmount = _amounts[0] + _premiums[0];
_flashLoanLogic(_data, _repayAmount);
return true;
}
/***************************** Aave flash loan functions ends ***********************************/
/***************************** DyDx flash loan functions ***************************************/
/**
* @notice This is entry point for DyDx flash loan
* @param _token Token for which we are taking flash loan
* @param _amountDesired Flash loan amount
* @param _data This will be passed downstream for processing. It can be empty.
*/
function _doDyDxFlashLoan(
address _token,
uint256 _amountDesired,
bytes memory _data
) internal returns (uint256 _amount) {
require(isDyDxActive, "dydx-flash-loan-is-not-active");
_amount = _amountDesired;
// Check token liquidity in DyDx
uint256 amountInSolo = IERC20(_token).balanceOf(SOLO);
if (_amount > amountInSolo) {
_amount = amountInSolo;
}
// Repay amount, amount with fee, can be 2 wei higher. Consider 2 wei as fee
uint256 repayAmount = _amount + 2;
// Encode custom data for callFunction
bytes memory _callData = abi.encode(_data, repayAmount);
// 1. Withdraw _token
// 2. Call callFunction(...) which will call loanLogic
// 3. Deposit _token back
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
operations[0] = _getWithdrawAction(dyDxMarketId, _amount);
operations[1] = _getCallAction(_callData);
operations[2] = _getDepositAction(dyDxMarketId, repayAmount);
Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();
ISoloMargin(SOLO).operate(accountInfos, operations);
}
/// @dev DyDx calls this function after doing flash loan
function callFunction(
address,
/* _sender */
Account.Info memory, /* _account */
bytes memory _callData
) external {
(bytes memory _data, uint256 _repayAmount) = abi.decode(_callData, (bytes, uint256));
require(msg.sender == SOLO, "NOT_SOLO");
_flashLoanLogic(_data, _repayAmount);
}
/********************************* DyDx helper functions *********************************/
function _getAccountInfo() internal view returns (Account.Info memory) {
return Account.Info({owner: address(this), number: 1});
}
function _getMarketIdFromTokenAddress(address _solo, address token) internal view returns (uint256) {
ISoloMargin solo = ISoloMargin(_solo);
uint256 numMarkets = solo.getNumMarkets();
address curToken;
for (uint256 i = 0; i < numMarkets; i++) {
curToken = solo.getMarketTokenAddress(i);
if (curToken == token) {
return i;
}
}
revert("no-marketId-found-for-token");
}
function _getWithdrawAction(uint256 marketId, uint256 amount) internal view returns (Actions.ActionArgs memory) {
return
Actions.ActionArgs({
actionType: Actions.ActionType.Withdraw,
accountId: 0,
amount: Types.AssetAmount({
sign: false,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: amount
}),
primaryMarketId: marketId,
secondaryMarketId: 0,
otherAddress: address(this),
otherAccountId: 0,
data: ""
});
}
function _getCallAction(bytes memory data) internal view returns (Actions.ActionArgs memory) {
return
Actions.ActionArgs({
actionType: Actions.ActionType.Call,
accountId: 0,
amount: Types.AssetAmount({
sign: false,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: 0
}),
primaryMarketId: 0,
secondaryMarketId: 0,
otherAddress: address(this),
otherAccountId: 0,
data: data
});
}
function _getDepositAction(uint256 marketId, uint256 amount) internal view returns (Actions.ActionArgs memory) {
return
Actions.ActionArgs({
actionType: Actions.ActionType.Deposit,
accountId: 0,
amount: Types.AssetAmount({
sign: true,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: amount
}),
primaryMarketId: marketId,
secondaryMarketId: 0,
otherAddress: address(this),
otherAccountId: 0,
data: ""
});
}
/***************************** DyDx flash loan functions end *****************************/
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface AaveLendingPoolAddressesProvider {
function getLendingPool() external view returns (address);
function getAddress(bytes32 id) external view returns (address);
}
interface AToken is IERC20 {
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view returns (address);
}
interface AaveIncentivesController {
function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256);
function claimRewards(
address[] calldata assets,
uint256 amount,
address to
) external returns (uint256);
}
interface AaveLendingPool {
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
function withdraw(
address asset,
uint256 amount,
address to
) external returns (uint256);
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
}
interface AaveProtocolDataProvider {
function getReserveTokensAddresses(address asset)
external
view
returns (
address aTokenAddress,
address stableDebtTokenAddress,
address variableDebtTokenAddress
);
function getReserveData(address asset)
external
view
returns (
uint256 availableLiquidity,
uint256 totalStableDebt,
uint256 totalVariableDebt,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 lastUpdateTimestamp
);
}
//solhint-disable func-name-mixedcase
interface StakedAave is IERC20 {
function claimRewards(address to, uint256 amount) external;
function cooldown() external;
function stake(address onBehalfOf, uint256 amount) external;
function redeem(address to, uint256 amount) external;
function getTotalRewardsBalance(address staker) external view returns (uint256);
function stakersCooldowns(address staker) external view returns (uint256);
function COOLDOWN_SECONDS() external view returns (uint256);
function UNSTAKE_WINDOW() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
interface IAddressList {
function add(address a) external returns (bool);
function remove(address a) external returns (bool);
function get(address a) external view returns (uint256);
function contains(address a) external view returns (bool);
function length() external view returns (uint256);
function grantRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
interface IAddressListFactory {
function ours(address a) external view returns (bool);
function listCount() external view returns (uint256);
function listAt(uint256 idx) external view returns (address);
function createList() external returns (address listaddr);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
/* solhint-disable func-name-mixedcase */
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
interface ISwapManager {
event OracleCreated(address indexed _sender, address indexed _newOracle, uint256 _period);
function N_DEX() external view returns (uint256);
function ROUTERS(uint256 i) external view returns (IUniswapV2Router02);
function bestOutputFixedInput(
address _from,
address _to,
uint256 _amountIn
)
external
view
returns (
address[] memory path,
uint256 amountOut,
uint256 rIdx
);
function bestPathFixedInput(
address _from,
address _to,
uint256 _amountIn,
uint256 _i
) external view returns (address[] memory path, uint256 amountOut);
function bestInputFixedOutput(
address _from,
address _to,
uint256 _amountOut
)
external
view
returns (
address[] memory path,
uint256 amountIn,
uint256 rIdx
);
function bestPathFixedOutput(
address _from,
address _to,
uint256 _amountOut,
uint256 _i
) external view returns (address[] memory path, uint256 amountIn);
function safeGetAmountsOut(
uint256 _amountIn,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function unsafeGetAmountsOut(
uint256 _amountIn,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function safeGetAmountsIn(
uint256 _amountOut,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function unsafeGetAmountsIn(
uint256 _amountOut,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function comparePathsFixedInput(
address[] memory pathA,
address[] memory pathB,
uint256 _amountIn,
uint256 _i
) external view returns (address[] memory path, uint256 amountOut);
function comparePathsFixedOutput(
address[] memory pathA,
address[] memory pathB,
uint256 _amountOut,
uint256 _i
) external view returns (address[] memory path, uint256 amountIn);
function ours(address a) external view returns (bool);
function oracleCount() external view returns (uint256);
function oracleAt(uint256 idx) external view returns (address);
function getOracle(
address _tokenA,
address _tokenB,
uint256 _period,
uint256 _i
) external view returns (address);
function createOrUpdateOracle(
address _tokenA,
address _tokenB,
uint256 _period,
uint256 _i
) external returns (address oracleAddr);
function consultForFree(
address _from,
address _to,
uint256 _amountIn,
uint256 _period,
uint256 _i
) external view returns (uint256 amountOut, uint256 lastUpdatedAt);
/// get the data we want and pay the gas to update
function consult(
address _from,
address _to,
uint256 _amountIn,
uint256 _period,
uint256 _i
)
external
returns (
uint256 amountOut,
uint256 lastUpdatedAt,
bool updated
);
function updateOracles() external returns (uint256 updated, uint256 expected);
function updateOracles(address[] memory _oracleAddrs) external returns (uint256 updated, uint256 expected);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
interface CToken {
function accrueInterest() external returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function balanceOfUnderlying(address owner) 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 getAccountSnapshot(address account)
external
view
returns (
uint256,
uint256,
uint256,
uint256
);
function borrow(uint256 borrowAmount) external returns (uint256);
function mint() external payable; // For ETH
function mint(uint256 mintAmount) external returns (uint256); // For ERC20
function redeem(uint256 redeemTokens) external returns (uint256);
function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
function repayBorrow() external payable; // For ETH
function repayBorrow(uint256 repayAmount) external returns (uint256); // For ERC20
function transfer(address user, uint256 amount) external returns (bool);
function getCash() external view returns (uint256);
function transferFrom(
address owner,
address user,
uint256 amount
) external returns (bool);
function underlying() external view returns (address);
}
interface Comptroller {
function claimComp(address holder, address[] memory) external;
function enterMarkets(address[] memory cTokens) external returns (uint256[] memory);
function exitMarket(address cToken) external returns (uint256);
function compAccrued(address holder) external view returns (uint256);
function getAccountLiquidity(address account)
external
view
returns (
uint256,
uint256,
uint256
);
function markets(address market)
external
view
returns (
bool isListed,
uint256 collateralFactorMantissa,
bool isCompted
);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
/** In order to keep code/files short, all libraries and interfaces are trimmed as per Vesper need */
library Account {
enum Status {Normal, Liquid, Vapor}
struct Info {
address owner; // The address that owns the account
uint256 number; // A nonce that allows a single address to control many accounts
}
}
library Actions {
enum ActionType {
Deposit, // supply tokens
Withdraw, // borrow tokens
Transfer, // transfer balance between accounts
Buy, // buy an amount of some token (publicly)
Sell, // sell an amount of some token (publicly)
Trade, // trade tokens against another account
Liquidate, // liquidate an undercollateralized or expiring account
Vaporize, // use excess tokens to zero-out a completely negative account
Call // send arbitrary data to an address
}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
Types.AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
}
library Types {
enum AssetDenomination {
Wei, // the amount is denominated in wei
Par // the amount is denominated in par
}
enum AssetReference {
Delta, // the amount is given as a delta from the current value
Target // the amount is given as an exact number to end up at
}
struct AssetAmount {
bool sign; // true if positive
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
}
interface ISoloMargin {
function getMarketTokenAddress(uint256 marketId) external view returns (address);
function getNumMarkets() external view returns (uint256);
function operate(Account.Info[] memory accounts, Actions.ActionArgs[] memory actions) external;
}
/**
* @title ICallee
* @author dYdX
*
* Interface that Callees for Solo must implement in order to ingest data.
*/
interface ICallee {
// ============ Public Functions ============
/**
* Allows users to send this contract arbitrary data.
*
* @param sender The msg.sender to Solo
* @param accountInfo The account from which the data is being sent
* @param data Arbitrary data given by the sender
*/
function callFunction(
address sender,
Account.Info memory accountInfo,
bytes memory data
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
// Interface to use 3rd party Uniswap V3 oracle utility contract deployed at https://etherscan.io/address/0x0f1f5a87f99f0918e6c81f16e59f3518698221ff#code
/// @title UniswapV3 oracle with ability to query across an intermediate liquidity pool
interface IUniswapV3Oracle {
function assetToEth(
address _tokenIn,
uint256 _amountIn,
uint32 _twapPeriod
) external view returns (uint256 ethAmountOut);
function ethToAsset(
uint256 _ethAmountIn,
address _tokenOut,
uint32 _twapPeriod
) external view returns (uint256 amountOut);
function assetToAsset(
address _tokenIn,
uint256 _amountIn,
address _tokenOut,
uint32 _twapPeriod
) external view returns (uint256 amountOut);
function assetToAssetThruRoute(
address _tokenIn,
uint256 _amountIn,
address _tokenOut,
uint32 _twapPeriod,
address _routeThruToken,
uint24[2] memory _poolFees
) external view returns (uint256 amountOut);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface TokenLike is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
interface IStrategy {
function rebalance() external;
function sweepERC20(address _fromToken) external;
function withdraw(uint256 _amount) external;
function feeCollector() external view returns (address);
function isReservedToken(address _token) external view returns (bool);
function migrate(address _newStrategy) external;
function token() external view returns (address);
function totalValue() external view returns (uint256);
function totalValueCurrent() external returns (uint256);
function pool() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../bloq/IAddressList.sol";
interface IVesperPool is IERC20 {
function deposit() external payable;
function deposit(uint256 _share) external;
function multiTransfer(address[] memory _recipients, uint256[] memory _amounts) external returns (bool);
function excessDebt(address _strategy) external view returns (uint256);
function permit(
address,
address,
uint256,
uint256,
uint8,
bytes32,
bytes32
) external;
function poolRewards() external returns (address);
function reportEarning(
uint256 _profit,
uint256 _loss,
uint256 _payback
) external;
function reportLoss(uint256 _loss) external;
function resetApproval() external;
function sweepERC20(address _fromToken) external;
function withdraw(uint256 _amount) external;
function withdrawETH(uint256 _amount) external;
function whitelistedWithdraw(uint256 _amount) external;
function governor() external view returns (address);
function keepers() external view returns (IAddressList);
function maintainers() external view returns (IAddressList);
function feeCollector() external view returns (address);
function pricePerShare() external view returns (uint256);
function strategy(address _strategy)
external
view
returns (
bool _active,
uint256 _interestFee,
uint256 _debtRate,
uint256 _lastRebalance,
uint256 _totalDebt,
uint256 _totalLoss,
uint256 _totalProfit,
uint256 _debtRatio
);
function stopEverything() external view returns (bool);
function token() external view returns (IERC20);
function tokensHere() external view returns (uint256);
function totalDebtOf(address _strategy) external view returns (uint256);
function totalValue() external view returns (uint256);
function withdrawFee() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "../interfaces/bloq/ISwapManager.sol";
import "../interfaces/bloq/IAddressList.sol";
import "../interfaces/bloq/IAddressListFactory.sol";
import "../interfaces/vesper/IStrategy.sol";
import "../interfaces/vesper/IVesperPool.sol";
abstract contract Strategy is IStrategy, Context {
using SafeERC20 for IERC20;
IERC20 public immutable collateralToken;
address public receiptToken;
address public immutable override pool;
IAddressList public keepers;
address public override feeCollector;
ISwapManager public swapManager;
uint256 public oraclePeriod = 3600; // 1h
uint256 public oracleRouterIdx = 0; // Uniswap V2
uint256 public swapSlippage = 10000; // 100% Don't use oracles by default
address internal constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
uint256 internal constant MAX_UINT_VALUE = type(uint256).max;
event UpdatedFeeCollector(address indexed previousFeeCollector, address indexed newFeeCollector);
event UpdatedSwapManager(address indexed previousSwapManager, address indexed newSwapManager);
event UpdatedSwapSlippage(uint256 oldSwapSlippage, uint256 newSwapSlippage);
event UpdatedOracleConfig(uint256 oldPeriod, uint256 newPeriod, uint256 oldRouterIdx, uint256 newRouterIdx);
constructor(
address _pool,
address _swapManager,
address _receiptToken
) {
require(_pool != address(0), "pool-address-is-zero");
require(_swapManager != address(0), "sm-address-is-zero");
swapManager = ISwapManager(_swapManager);
pool = _pool;
collateralToken = IVesperPool(_pool).token();
receiptToken = _receiptToken;
}
modifier onlyGovernor {
require(_msgSender() == IVesperPool(pool).governor(), "caller-is-not-the-governor");
_;
}
modifier onlyKeeper() {
require(keepers.contains(_msgSender()), "caller-is-not-a-keeper");
_;
}
modifier onlyPool() {
require(_msgSender() == pool, "caller-is-not-vesper-pool");
_;
}
/**
* @notice Add given address in keepers list.
* @param _keeperAddress keeper address to add.
*/
function addKeeper(address _keeperAddress) external onlyGovernor {
require(keepers.add(_keeperAddress), "add-keeper-failed");
}
/**
* @notice Create keeper list
* NOTE: Any function with onlyKeeper modifier will not work until this function is called.
* NOTE: Due to gas constraint this function cannot be called in constructor.
* @param _addressListFactory To support same code in eth side chain, user _addressListFactory as param
* ethereum- 0xded8217De022706A191eE7Ee0Dc9df1185Fb5dA3
* polygon-0xD10D5696A350D65A9AA15FE8B258caB4ab1bF291
*/
function init(address _addressListFactory) external onlyGovernor {
require(address(keepers) == address(0), "keeper-list-already-created");
// Prepare keeper list
IAddressListFactory _factory = IAddressListFactory(_addressListFactory);
keepers = IAddressList(_factory.createList());
require(keepers.add(_msgSender()), "add-keeper-failed");
}
/**
* @notice Migrate all asset and vault ownership,if any, to new strategy
* @dev _beforeMigration hook can be implemented in child strategy to do extra steps.
* @param _newStrategy Address of new strategy
*/
function migrate(address _newStrategy) external virtual override onlyPool {
require(_newStrategy != address(0), "new-strategy-address-is-zero");
require(IStrategy(_newStrategy).pool() == pool, "not-valid-new-strategy");
_beforeMigration(_newStrategy);
IERC20(receiptToken).safeTransfer(_newStrategy, IERC20(receiptToken).balanceOf(address(this)));
collateralToken.safeTransfer(_newStrategy, collateralToken.balanceOf(address(this)));
}
/**
* @notice Remove given address from keepers list.
* @param _keeperAddress keeper address to remove.
*/
function removeKeeper(address _keeperAddress) external onlyGovernor {
require(keepers.remove(_keeperAddress), "remove-keeper-failed");
}
/**
* @notice Update fee collector
* @param _feeCollector fee collector address
*/
function updateFeeCollector(address _feeCollector) external onlyGovernor {
require(_feeCollector != address(0), "fee-collector-address-is-zero");
require(_feeCollector != feeCollector, "fee-collector-is-same");
emit UpdatedFeeCollector(feeCollector, _feeCollector);
feeCollector = _feeCollector;
}
/**
* @notice Update swap manager address
* @param _swapManager swap manager address
*/
function updateSwapManager(address _swapManager) external onlyGovernor {
require(_swapManager != address(0), "sm-address-is-zero");
require(_swapManager != address(swapManager), "sm-is-same");
emit UpdatedSwapManager(address(swapManager), _swapManager);
swapManager = ISwapManager(_swapManager);
}
function updateSwapSlippage(uint256 _newSwapSlippage) external onlyGovernor {
require(_newSwapSlippage <= 10000, "invalid-slippage-value");
emit UpdatedSwapSlippage(swapSlippage, _newSwapSlippage);
swapSlippage = _newSwapSlippage;
}
function updateOracleConfig(uint256 _newPeriod, uint256 _newRouterIdx) external onlyGovernor {
require(_newRouterIdx < swapManager.N_DEX(), "invalid-router-index");
if (_newPeriod == 0) _newPeriod = oraclePeriod;
require(_newPeriod > 59, "invalid-oracle-period");
emit UpdatedOracleConfig(oraclePeriod, _newPeriod, oracleRouterIdx, _newRouterIdx);
oraclePeriod = _newPeriod;
oracleRouterIdx = _newRouterIdx;
}
/// @dev Approve all required tokens
function approveToken() external onlyKeeper {
_approveToken(0);
_approveToken(MAX_UINT_VALUE);
}
function setupOracles() external onlyKeeper {
_setupOracles();
}
/**
* @dev Withdraw collateral token from lending pool.
* @param _amount Amount of collateral token
*/
function withdraw(uint256 _amount) external override onlyPool {
_withdraw(_amount);
}
/**
* @dev Rebalance profit, loss and investment of this strategy
*/
function rebalance() external virtual override onlyKeeper {
(uint256 _profit, uint256 _loss, uint256 _payback) = _generateReport();
IVesperPool(pool).reportEarning(_profit, _loss, _payback);
_reinvest();
}
/**
* @dev sweep given token to feeCollector of strategy
* @param _fromToken token address to sweep
*/
function sweepERC20(address _fromToken) external override onlyKeeper {
require(feeCollector != address(0), "fee-collector-not-set");
require(_fromToken != address(collateralToken), "not-allowed-to-sweep-collateral");
require(!isReservedToken(_fromToken), "not-allowed-to-sweep");
if (_fromToken == ETH) {
Address.sendValue(payable(feeCollector), address(this).balance);
} else {
uint256 _amount = IERC20(_fromToken).balanceOf(address(this));
IERC20(_fromToken).safeTransfer(feeCollector, _amount);
}
}
/// @notice Returns address of token correspond to collateral token
function token() external view override returns (address) {
return receiptToken;
}
/// @dev Convert from 18 decimals to token defined decimals. Default no conversion.
function convertFrom18(uint256 amount) public pure virtual returns (uint256) {
return amount;
}
/**
* @notice Calculate total value of asset under management
* @dev Report total value in collateral token
*/
function totalValue() public view virtual override returns (uint256 _value);
/**
* @notice Calculate total value of asset under management (in real-time)
* @dev Report total value in collateral token
*/
function totalValueCurrent() external virtual override returns (uint256) {
return totalValue();
}
/// @notice Check whether given token is reserved or not. Reserved tokens are not allowed to sweep.
function isReservedToken(address _token) public view virtual override returns (bool);
/**
* @notice some strategy may want to prepare before doing migration.
Example In Maker old strategy want to give vault ownership to new strategy
* @param _newStrategy .
*/
function _beforeMigration(address _newStrategy) internal virtual;
/**
* @notice Generate report for current profit and loss. Also liquidate asset to payback
* excess debt, if any.
* @return _profit Calculate any realized profit and convert it to collateral, if not already.
* @return _loss Calculate any loss that strategy has made on investment. Convert into collateral token.
* @return _payback If strategy has any excess debt, we have to liquidate asset to payback excess debt.
*/
function _generateReport()
internal
virtual
returns (
uint256 _profit,
uint256 _loss,
uint256 _payback
)
{
uint256 _excessDebt = IVesperPool(pool).excessDebt(address(this));
uint256 _totalDebt = IVesperPool(pool).totalDebtOf(address(this));
_profit = _realizeProfit(_totalDebt);
_loss = _realizeLoss(_totalDebt);
_payback = _liquidate(_excessDebt);
}
function _calcAmtOutAfterSlippage(uint256 _amount, uint256 _slippage) internal pure returns (uint256) {
return (_amount * (10000 - _slippage)) / (10000);
}
function _simpleOraclePath(address _from, address _to) internal pure returns (address[] memory path) {
if (_from == WETH || _to == WETH) {
path = new address[](2);
path[0] = _from;
path[1] = _to;
} else {
path = new address[](3);
path[0] = _from;
path[1] = WETH;
path[2] = _to;
}
}
function _consultOracle(
address _from,
address _to,
uint256 _amt
) internal returns (uint256, bool) {
// from, to, amountIn, period, router
(uint256 rate, uint256 lastUpdate, ) = swapManager.consult(_from, _to, _amt, oraclePeriod, oracleRouterIdx);
// We're looking at a TWAP ORACLE with a 1 hr Period that has been updated within the last hour
if ((lastUpdate > (block.timestamp - oraclePeriod)) && (rate != 0)) return (rate, true);
return (0, false);
}
function _getOracleRate(address[] memory path, uint256 _amountIn) internal returns (uint256 amountOut) {
require(path.length > 1, "invalid-oracle-path");
amountOut = _amountIn;
bool isValid;
for (uint256 i = 0; i < path.length - 1; i++) {
(amountOut, isValid) = _consultOracle(path[i], path[i + 1], amountOut);
require(isValid, "invalid-oracle-rate");
}
}
/**
* @notice Safe swap via Uniswap / Sushiswap (better rate of the two)
* @dev There are many scenarios when token swap via Uniswap can fail, so this
* method will wrap Uniswap call in a 'try catch' to make it fail safe.
* however, this method will throw minAmountOut is not met
* @param _from address of from token
* @param _to address of to token
* @param _amountIn Amount to be swapped
* @param _minAmountOut minimum amount out
*/
function _safeSwap(
address _from,
address _to,
uint256 _amountIn,
uint256 _minAmountOut
) internal {
(address[] memory path, uint256 amountOut, uint256 rIdx) =
swapManager.bestOutputFixedInput(_from, _to, _amountIn);
if (_minAmountOut == 0) _minAmountOut = 1;
if (amountOut != 0) {
swapManager.ROUTERS(rIdx).swapExactTokensForTokens(
_amountIn,
_minAmountOut,
path,
address(this),
block.timestamp
);
}
}
// These methods can be implemented by the inheriting strategy.
/* solhint-disable no-empty-blocks */
function _claimRewardsAndConvertTo(address _toToken) internal virtual {}
/**
* @notice Set up any oracles that are needed for this strategy.
*/
function _setupOracles() internal virtual {}
/* solhint-enable */
// These methods must be implemented by the inheriting strategy
function _withdraw(uint256 _amount) internal virtual;
function _approveToken(uint256 _amount) internal virtual;
/**
* @notice Withdraw collateral to payback excess debt in pool.
* @param _excessDebt Excess debt of strategy in collateral token
* @return _payback amount in collateral token. Usually it is equal to excess debt.
*/
function _liquidate(uint256 _excessDebt) internal virtual returns (uint256 _payback);
/**
* @notice Calculate earning and withdraw/convert it into collateral token.
* @param _totalDebt Total collateral debt of this strategy
* @return _profit Profit in collateral token
*/
function _realizeProfit(uint256 _totalDebt) internal virtual returns (uint256 _profit);
/**
* @notice Calculate loss
* @param _totalDebt Total collateral debt of this strategy
* @return _loss Realized loss in collateral token
*/
function _realizeLoss(uint256 _totalDebt) internal virtual returns (uint256 _loss);
/**
* @notice Reinvest collateral.
* @dev Once we file report back in pool, we might have some collateral in hand
* which we want to reinvest aka deposit in lender/provider.
*/
function _reinvest() internal virtual;
}// SPDX-License-Identifier: GNU LGPLv3
// Heavily inspired from CompoundLeverage strategy of Yearn. https://etherscan.io/address/0x4031afd3B0F71Bace9181E554A9E680Ee4AbE7dF#code
pragma solidity 0.8.3;
import "../Strategy.sol";
import "../../interfaces/compound/ICompound.sol";
import "../../interfaces/oracle/IUniswapV3Oracle.sol";
import "../../FlashLoanHelper.sol";
/// @title This strategy will deposit collateral token in Compound and based on position
/// it will borrow same collateral token. It will use borrowed asset as supply and borrow again.
abstract contract CompoundLeverageStrategy is Strategy, FlashLoanHelper {
using SafeERC20 for IERC20;
uint256 internal constant MAX_BPS = 10_000; //100%
uint256 public minBorrowLimit = 7_000; // 70%
uint256 public maxBorrowLimit = 9_000; // 90%
CToken internal cToken;
address internal constant COMP = 0xc00e94Cb662C3520282E6f5717214004A7f26888;
Comptroller internal constant COMPTROLLER = Comptroller(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);
IUniswapV3Oracle internal constant ORACLE = IUniswapV3Oracle(0x0F1f5A87f99f0918e6C81F16E59F3518698221Ff);
uint32 internal constant TWAP_PERIOD = 3600;
constructor(
address _pool,
address _swapManager,
address _receiptToken
) Strategy(_pool, _swapManager, _receiptToken) {
require(_receiptToken != address(0), "cToken-address-is-zero");
cToken = CToken(_receiptToken);
}
/**
* @notice Update upper and lower borrow limit
* @dev It is possible to set 0 as _minBorrowLimit to not borrow anything
* @param _minBorrowLimit Minimum % we want to borrow
* @param _maxBorrowLimit Maximum % we want to borrow
*/
function updateBorrowLimit(uint256 _minBorrowLimit, uint256 _maxBorrowLimit) external onlyGovernor {
require(_maxBorrowLimit < MAX_BPS, "invalid-max-borrow-limit");
require(_maxBorrowLimit > _minBorrowLimit, "max-should-be-higher-than-min");
minBorrowLimit = _minBorrowLimit;
maxBorrowLimit = _maxBorrowLimit;
}
function updateAaveStatus(bool _status) external onlyGovernor {
_updateAaveStatus(_status);
}
function updateDyDxStatus(bool _status) external onlyGovernor {
_updateDyDxStatus(_status, address(collateralToken));
}
/**
* @notice Calculate total value based on COMP claimed, supply and borrow position
* @dev Report total value in collateral token
* @dev Claimed COMP will stay in strategy until next rebalance
*/
function totalValueCurrent() external override returns (uint256 _totalValue) {
cToken.exchangeRateCurrent();
_claimComp();
_totalValue = _calculateTotalValue(IERC20(COMP).balanceOf(address(this)));
}
/**
* @notice Calculate and return borrow ratio range.
* @dev It is calculated as collateralFactor * borrowLimit
*/
function borrowRatioRange() public view returns (uint256 _minBorrowRatio, uint256 _maxBorrowRatio) {
(, uint256 _collateralFactor, ) = COMPTROLLER.markets(address(cToken));
_minBorrowRatio = (minBorrowLimit * _collateralFactor) / 1e18;
_maxBorrowRatio = (maxBorrowLimit * _collateralFactor) / 1e18;
}
/**
* @notice Current borrow ratio, calculated as current borrow divide by max allowed borrow
* Return value is based on basis points, i.e. 7500 = 75% ratio
*/
function currentBorrowRatio() external view returns (uint256) {
(uint256 _supply, uint256 _borrow) = getPosition();
return _borrow == 0 ? 0 : (_borrow * MAX_BPS) / _supply;
}
/**
* @notice Calculate total value using COMP accrued, supply and borrow position
* @dev Compound calculate COMP accrued and store it when user interact with
* Compound contracts, i.e. deposit, withdraw or transfer tokens.
* So compAccrued() will return stored COMP accrued amount, which is older
* @dev For up to date value check totalValueCurrent()
*/
function totalValue() public view virtual override returns (uint256 _totalValue) {
_totalValue = _calculateTotalValue(COMPTROLLER.compAccrued(address(this)));
}
/**
* @notice Calculate current position using claimed COMP and current borrow.
*/
function isLossMaking() external returns (bool) {
_claimComp();
(, uint256 _compAsCollateral, ) =
swapManager.bestOutputFixedInput(COMP, address(collateralToken), IERC20(COMP).balanceOf(address(this)));
uint256 _totalDebt = IVesperPool(pool).totalDebtOf(address(this));
(uint256 _supply, uint256 _borrow) = getPosition();
uint256 _collateralHere = collateralToken.balanceOf(address(this));
uint256 _totalCollateral = _collateralHere + _compAsCollateral + _supply - _borrow;
return _totalCollateral < _totalDebt;
}
function isReservedToken(address _token) public view virtual override returns (bool) {
return _token == address(cToken) || _token == COMP || _token == address(collateralToken);
}
/// @notice Return supply and borrow position. Position may return few block old value
function getPosition() public view returns (uint256 _supply, uint256 _borrow) {
(, uint256 _cTokenBalance, uint256 _borrowBalance, uint256 _exchangeRate) =
cToken.getAccountSnapshot(address(this));
_supply = (_cTokenBalance * _exchangeRate) / 1e18;
_borrow = _borrowBalance;
}
/// @notice Approve all required tokens
function _approveToken(uint256 _amount) internal virtual override {
collateralToken.safeApprove(pool, _amount);
collateralToken.safeApprove(address(cToken), _amount);
for (uint256 i = 0; i < swapManager.N_DEX(); i++) {
IERC20(COMP).safeApprove(address(swapManager.ROUTERS(i)), _amount);
}
FlashLoanHelper._approveToken(address(collateralToken), _amount);
}
/**
* @notice Claim COMP and transfer to new strategy
* @param _newStrategy Address of new strategy.
*/
function _beforeMigration(address _newStrategy) internal virtual override {
require(IStrategy(_newStrategy).token() == address(cToken), "wrong-receipt-token");
minBorrowLimit = 0;
// It will calculate amount to repay based on borrow limit and payback all
_reinvest();
}
/**
* @notice Calculate borrow position based on borrow ratio, current supply, borrow, amount
* being deposited or withdrawn.
* @param _amount Collateral amount
* @param _isDeposit Flag indicating whether we are depositing _amount or withdrawing
* @return _position Amount of borrow that need to be adjusted
* @return _shouldRepay Flag indicating whether _position is borrow amount or repay amount
*/
function _calculateDesiredPosition(uint256 _amount, bool _isDeposit)
internal
returns (uint256 _position, bool _shouldRepay)
{
uint256 _totalSupply = cToken.balanceOfUnderlying(address(this));
uint256 _currentBorrow = cToken.borrowBalanceStored(address(this));
// If minimum borrow limit set to 0 then repay borrow
if (minBorrowLimit == 0) {
return (_currentBorrow, true);
}
uint256 _supply = _totalSupply - _currentBorrow;
// In case of withdraw, _amount can be greater than _supply
uint256 _newSupply = _isDeposit ? _supply + _amount : _supply > _amount ? _supply - _amount : 0;
(uint256 _minBorrowRatio, uint256 _maxBorrowRatio) = borrowRatioRange();
// (supply * borrowRatio)/(BPS - borrowRatio)
uint256 _borrowUpperBound = (_newSupply * _maxBorrowRatio) / (MAX_BPS - _maxBorrowRatio);
uint256 _borrowLowerBound = (_newSupply * _minBorrowRatio) / (MAX_BPS - _minBorrowRatio);
// If our current borrow is greater than max borrow allowed, then we will have to repay
// some to achieve safe position else borrow more.
if (_currentBorrow > _borrowUpperBound) {
_shouldRepay = true;
// If borrow > upperBound then it is greater than lowerBound too.
_position = _currentBorrow - _borrowLowerBound;
} else if (_currentBorrow < _borrowLowerBound) {
_shouldRepay = false;
// We can borrow more.
_position = _borrowLowerBound - _currentBorrow;
}
}
/**
* @dev COMP is converted to collateral and if we have some borrow interest to pay,
* it will go come from collateral.
* @dev Report total value in collateral token
*/
function _calculateTotalValue(uint256 _compAccrued) internal view returns (uint256 _totalValue) {
uint256 _compAsCollateral;
if (_compAccrued != 0) {
(, _compAsCollateral, ) = swapManager.bestOutputFixedInput(COMP, address(collateralToken), _compAccrued);
}
(uint256 _supply, uint256 _borrow) = getPosition();
_totalValue = _compAsCollateral + collateralToken.balanceOf(address(this)) + _supply - _borrow;
}
/// @notice Claim comp
function _claimComp() internal {
address[] memory _markets = new address[](1);
_markets[0] = address(cToken);
COMPTROLLER.claimComp(address(this), _markets);
}
/// @notice Claim COMP and convert COMP into collateral token.
function _claimRewardsAndConvertTo(address _toToken) internal override {
_claimComp();
uint256 _compAmount = IERC20(COMP).balanceOf(address(this));
if (_compAmount != 0) {
_safeSwap(COMP, _toToken, _compAmount);
}
}
/**
* @notice Generate report for pools accounting and also send profit and any payback to pool.
* @dev Claim COMP and convert to collateral.
*/
function _generateReport()
internal
override
returns (
uint256 _profit,
uint256 _loss,
uint256 _payback
)
{
uint256 _excessDebt = IVesperPool(pool).excessDebt(address(this));
uint256 _totalDebt = IVesperPool(pool).totalDebtOf(address(this));
// Claim COMP and convert to collateral token
_claimRewardsAndConvertTo(address(collateralToken));
uint256 _supply = cToken.balanceOfUnderlying(address(this));
uint256 _borrow = cToken.borrowBalanceStored(address(this));
uint256 _investedCollateral = _supply - _borrow;
uint256 _collateralHere = collateralToken.balanceOf(address(this));
uint256 _totalCollateral = _investedCollateral + _collateralHere;
uint256 _profitToWithdraw;
if (_totalCollateral > _totalDebt) {
_profit = _totalCollateral - _totalDebt;
if (_collateralHere <= _profit) {
_profitToWithdraw = _profit - _collateralHere;
} else if (_collateralHere >= (_profit + _excessDebt)) {
// Very rare scenario
_payback = _excessDebt;
} else {
// _profit < CollateralHere < _profit + _excessDebt
_payback = _collateralHere - _profit;
}
} else {
_loss = _totalDebt - _totalCollateral;
}
uint256 _paybackToWithdraw = _excessDebt - _payback;
uint256 _totalAmountToWithdraw = _paybackToWithdraw + _profitToWithdraw;
if (_totalAmountToWithdraw != 0) {
uint256 _withdrawn = _withdrawHere(_totalAmountToWithdraw);
// Any amount withdrawn over _profitToWithdraw is payback for pool
if (_withdrawn > _profitToWithdraw) {
_payback += (_withdrawn - _profitToWithdraw);
}
}
}
/**
* Adjust position by normal leverage and deleverage.
* @param _adjustBy Amount by which we want to increase or decrease _borrow
* @param _shouldRepay True indicate we want to deleverage
* @return amount Actual adjusted amount
*/
function _adjustPosition(uint256 _adjustBy, bool _shouldRepay) internal returns (uint256 amount) {
// We can get position via view function, as this function will be called after _calculateDesiredPosition
(uint256 _supply, uint256 _borrow) = getPosition();
// If no borrow then there is nothing to deleverage
if (_borrow == 0 && _shouldRepay) {
return 0;
}
(, uint256 collateralFactor, ) = COMPTROLLER.markets(address(cToken));
if (_shouldRepay) {
amount = _normalDeleverage(_adjustBy, _supply, _borrow, collateralFactor);
} else {
amount = _normalLeverage(_adjustBy, _supply, _borrow, collateralFactor);
}
}
/**
* Deleverage: Reduce borrow to achieve safe position
* @param _maxDeleverage Reduce borrow by this amount
* @return _deleveragedAmount Amount we actually reduced
*/
function _normalDeleverage(
uint256 _maxDeleverage,
uint256 _supply,
uint256 _borrow,
uint256 _collateralFactor
) internal returns (uint256 _deleveragedAmount) {
uint256 _theoreticalSupply;
if (_collateralFactor != 0) {
// Calculate minimum supply required to support _borrow
_theoreticalSupply = (_borrow * 1e18) / _collateralFactor;
}
_deleveragedAmount = _supply - _theoreticalSupply;
if (_deleveragedAmount >= _borrow) {
_deleveragedAmount = _borrow;
}
if (_deleveragedAmount >= _maxDeleverage) {
_deleveragedAmount = _maxDeleverage;
}
_redeemUnderlying(_deleveragedAmount);
_repayBorrow(_deleveragedAmount);
}
/**
* Leverage: Borrow more
* @param _maxLeverage Max amount to borrow
* @return _leveragedAmount Amount we actually borrowed
*/
function _normalLeverage(
uint256 _maxLeverage,
uint256 _supply,
uint256 _borrow,
uint256 _collateralFactor
) internal returns (uint256 _leveragedAmount) {
// Calculate maximum we can borrow at current _supply
uint256 theoreticalBorrow = (_supply * _collateralFactor) / 1e18;
_leveragedAmount = theoreticalBorrow - _borrow;
if (_leveragedAmount >= _maxLeverage) {
_leveragedAmount = _maxLeverage;
}
_borrowCollateral(_leveragedAmount);
_mint(collateralToken.balanceOf(address(this)));
}
/// @notice Deposit collateral in Compound and adjust borrow position
function _reinvest() internal virtual override {
uint256 _collateralBalance = collateralToken.balanceOf(address(this));
(uint256 _position, bool _shouldRepay) = _calculateDesiredPosition(_collateralBalance, true);
// Supply collateral to compound.
_mint(_collateralBalance);
// During reinvest, _shouldRepay will be false which indicate that we will borrow more.
// Due to more fee Aave flash loan is not used for borrow
if (isDyDxActive && _position > 0) {
bytes memory _data = abi.encode(_position, _shouldRepay);
_position -= _doDyDxFlashLoan(address(collateralToken), _position, _data);
}
uint256 i = 0;
while (_position > 0 && i <= 6) {
_position -= _adjustPosition(_position, _shouldRepay);
i++;
}
}
/// @dev Withdraw collateral and transfer it to pool
function _withdraw(uint256 _amount) internal override {
collateralToken.safeTransfer(pool, _withdrawHere(_amount));
}
/// @dev Withdraw collateral here. Do not transfer to pool
function _withdrawHere(uint256 _amount) internal returns (uint256) {
(uint256 _position, bool _shouldRepay) = _calculateDesiredPosition(_amount, false);
if (_shouldRepay) {
// Due to less fee DyDx is our primary flash loan provider
if (isDyDxActive) {
bytes memory _data = abi.encode(_position, _shouldRepay);
_position -= _doDyDxFlashLoan(address(collateralToken), _position, _data);
}
// Do aave flash loan if needed
if (_position > 0 && isAaveActive) {
bytes memory _data = abi.encode(_position, _shouldRepay);
_position -= _doAaveFlashLoan(address(collateralToken), _position, _data);
}
// If we still have _position to deleverage do it via normal deleverage
uint256 i = 0;
while (_position > 0 && i <= 10) {
_position -= _adjustPosition(_position, true);
i++;
}
// There may be scenario where we are not able to deleverage enough
if (_position != 0) {
// Calculate redeemable at current borrow and supply.
(uint256 _supply, uint256 _borrow) = getPosition();
(, uint256 _maxBorrowRatio) = borrowRatioRange();
uint256 _supplyToSupportBorrow;
if (_maxBorrowRatio != 0) {
_supplyToSupportBorrow = (_borrow * MAX_BPS) / _maxBorrowRatio;
}
// Current supply minus supply required to support _borrow at _maxBorrowRatio
uint256 _redeemable = _supply - _supplyToSupportBorrow;
if (_amount > _redeemable) {
_amount = _redeemable;
}
}
}
uint256 _collateralBefore = collateralToken.balanceOf(address(this));
// If we do not have enough collateral, try to get some via COMP
// This scenario is rare and will happen during last withdraw
if (_amount > cToken.balanceOfUnderlying(address(this))) {
// Use all collateral for withdraw
_collateralBefore = 0;
_claimRewardsAndConvertTo(address(collateralToken));
// Updated amount
_amount = _amount - collateralToken.balanceOf(address(this));
}
_redeemUnderlying(_amount);
uint256 _collateralAfter = collateralToken.balanceOf(address(this));
return _collateralAfter - _collateralBefore;
}
/**
* @notice This function will be called by flash loan
* @dev In case of borrow, DyDx is preferred as fee is so low that it does not effect
* our collateralRatio and liquidation risk.
*/
function _flashLoanLogic(bytes memory _data, uint256 _repayAmount) internal override {
(uint256 _amount, bool _deficit) = abi.decode(_data, (uint256, bool));
uint256 _collateralHere = collateralToken.balanceOf(address(this));
require(_collateralHere >= _amount, "FLASH_FAILED"); // to stop malicious calls
//if in deficit we repay amount and then withdraw
if (_deficit) {
_repayBorrow(_amount);
//if we are withdrawing we take more to cover fee
_redeemUnderlying(_repayAmount);
} else {
_mint(_collateralHere);
//borrow more to cover fee
_borrowCollateral(_repayAmount);
}
}
/**
* @dev If swap slippage is defined then use oracle to get amountOut and calculate minAmountOut
*/
function _safeSwap(
address _tokenIn,
address _tokenOut,
uint256 _amountIn
) private {
uint256 _minAmountOut =
swapSlippage != 10000
? _calcAmtOutAfterSlippage(
ORACLE.assetToAsset(_tokenIn, _amountIn, _tokenOut, TWAP_PERIOD),
swapSlippage
)
: 1;
_safeSwap(_tokenIn, _tokenOut, _amountIn, _minAmountOut);
}
//////////////////// Compound wrapper functions //////////////////////////////
/**
* @dev Compound support ETH as collateral not WETH. So ETH strategy can override
* below functions and handle wrap/unwrap of WETH.
*/
function _mint(uint256 _amount) internal virtual {
require(cToken.mint(_amount) == 0, "supply-to-compound-failed");
}
function _redeemUnderlying(uint256 _amount) internal virtual {
require(cToken.redeemUnderlying(_amount) == 0, "withdraw-from-compound-failed");
}
function _borrowCollateral(uint256 _amount) internal virtual {
require(cToken.borrow(_amount) == 0, "borrow-from-compound-failed");
}
function _repayBorrow(uint256 _amount) internal virtual {
require(cToken.repayBorrow(_amount) == 0, "repay-to-compound-failed");
}
//////////////////////////////////////////////////////////////////////////////
/* solhint-disable no-empty-blocks */
// We overridden _generateReport which eliminates need of below function.
function _liquidate(uint256 _excessDebt) internal override returns (uint256 _payback) {}
function _realizeProfit(uint256 _totalDebt) internal virtual override returns (uint256) {}
function _realizeLoss(uint256 _totalDebt) internal view override returns (uint256 _loss) {}
/* solhint-enable no-empty-blocks */
}{
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address","name":"_swapManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousFeeCollector","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"UpdatedFeeCollector","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldRouterIdx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRouterIdx","type":"uint256"}],"name":"UpdatedOracleConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousSwapManager","type":"address"},{"indexed":true,"internalType":"address","name":"newSwapManager","type":"address"}],"name":"UpdatedSwapManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldSwapSlippage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSwapSlippage","type":"uint256"}],"name":"UpdatedSwapSlippage","type":"event"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeperAddress","type":"address"}],"name":"addKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"approveToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowRatioRange","outputs":[{"internalType":"uint256","name":"_minBorrowRatio","type":"uint256"},{"internalType":"uint256","name":"_maxBorrowRatio","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"number","type":"uint256"}],"internalType":"struct Account.Info","name":"","type":"tuple"},{"internalType":"bytes","name":"_callData","type":"bytes"}],"name":"callFunction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateralToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"convertFrom18","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"currentBorrowRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dyDxMarketId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"_premiums","type":"uint256[]"},{"internalType":"address","name":"_initiator","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPosition","outputs":[{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"uint256","name":"_borrow","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addressListFactory","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAaveActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDyDxActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLossMaking","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepers","outputs":[{"internalType":"contract IAddressList","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBorrowLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minBorrowLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oraclePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleRouterIdx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"receiptToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeperAddress","type":"address"}],"name":"removeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setupOracles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapManager","outputs":[{"internalType":"contract ISwapManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_fromToken","type":"address"}],"name":"sweepERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalValue","outputs":[{"internalType":"uint256","name":"_totalValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalValueCurrent","outputs":[{"internalType":"uint256","name":"_totalValue","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateAaveStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"_maxBorrowLimit","type":"uint256"}],"name":"updateBorrowLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateDyDxStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"updateFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPeriod","type":"uint256"},{"internalType":"uint256","name":"_newRouterIdx","type":"uint256"}],"name":"updateOracleConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapManager","type":"address"}],"name":"updateSwapManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newSwapSlippage","type":"uint256"}],"name":"updateSwapSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c0604052610e1060045560006005556127106006556008805462ffffff19169055611b58600955612328600a553480156200003a57600080fd5b506040516200601e3803806200601e8339810160408190526200005d9162000275565b81817335a18000230da775cac24873d00ff85bccded5508282826001600160a01b038316620000d35760405162461bcd60e51b815260206004820152601460248201527f706f6f6c2d616464726573732d69732d7a65726f00000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b038216620001205760405162461bcd60e51b8152602060048201526012602482015271736d2d616464726573732d69732d7a65726f60701b6044820152606401620000ca565b600380546001600160a01b0319166001600160a01b0384811691909117909155606084901b6001600160601b03191660a05260408051637e062a3560e11b815290519185169163fc0c546a91600480820192602092909190829003018186803b1580156200018d57600080fd5b505afa158015620001a2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c89190620002b3565b60601b6001600160601b031916608052600080546001600160a01b0319166001600160a01b039283161790558316151591506200024a90505760405162461bcd60e51b815260206004820152601660248201527f63546f6b656e2d616464726573732d69732d7a65726f000000000000000000006044820152606401620000ca565b600b80546001600160a01b0319166001600160a01b039290921691909117905550620002f292505050565b6000806040838503121562000288578182fd5b82516200029581620002d9565b6020840151909250620002a881620002d9565b809150509250929050565b600060208284031215620002c5578081fd5b8151620002d281620002d9565b9392505050565b6001600160a01b0381168114620002ef57600080fd5b50565b60805160601c60a05160601c615bd36200044b600039600081816102a4015281816105b901528181610748015281816109c301528181610a3f01528181610c3c01528181610def01528181610f19015281816111fe015281816117580152818161196e01528181611c4e01528181611d1701528181611f6c01528181612135015281816125fa01528181612769015281816127fa015281816128970152612f6101526000818161048c01528181610c0001528181610eb40152818161162f0152818161180401528181611ebf01528181611f43015281816123920152818161291801528181612a6c01528181612bd201528181612cc301528181612d7a01528181612f3f01528181612f97015281816131020152818161329f015281816133630152818161357d015281816135fe015281816136f4015281816138030152818161383c015281816138ec0152614cce0152615bd36000f3fe608060405234801561001057600080fd5b50600436106102695760003560e01c806399b71d5c11610151578063d4c3eea0116100c3578063f23c472211610087578063f23c472214610542578063f7c99bea14610554578063fb589de21461055d578063fb7ee1021461056e578063fc0c546a14610581578063ffa1ad741461059257610269565b8063d4c3eea014610503578063e00af4a71461050b578063e260d7471461051e578063e645c20214610527578063ec78e8321461052f57610269565b8063b2016bd411610115578063b2016bd414610487578063c415b95c146104ae578063cd2d7ebe146104c1578063ce5494bb146104ca578063d2c35ce8146104dd578063d3332539146104f057610269565b806399b71d5c1461040e5780639b7166a914610416578063a3f4df7e14610423578063a923b2a61461046c578063aa1018861461047f57610269565b8063599e892a116101ea5780637d7c2a1c116101ae5780637d7c2a1c146103bd5780638b418713146103c557806391d260e9146103d8578063920f5c84146103e057806392986024146103f3578063951dc22c146103fb57610269565b8063599e892a1461035f5780635abda0281461037257806367f5e4b81461037a578063709d039d1461038d5780637398ab18146103a057610269565b80632e1a7d4d116102315780632e1a7d4d146102fa5780634032b72b1461030d57806342189c8f14610320578063440d7248146103295780634c36fad71461034c57610269565b80630181686c1461026e57806314ae9f2e1461028a57806316f0115b1461029f57806319ab453c146102de5780631aedeabe146102f1575b600080fd5b610277600a5481565b6040519081526020015b60405180910390f35b61029d61029836600461516c565b6105b7565b005b6102c67f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610281565b61029d6102ec36600461516c565b610746565b61027760065481565b61029d6103083660046155a6565b6109c0565b61029d61031b36600461516c565b610a3d565b61027760045481565b61033c61033736600461516c565b610bbd565b6040519015158152602001610281565b61029d61035a36600461516c565b610c3a565b61029d61036d3660046154af565b610ded565b610277610ed8565b61029d6103883660046155a6565b610f17565b6003546102c6906001600160a01b031681565b6103a8611063565b60408051928352602083019190915201610281565b61029d611118565b61029d6103d33660046151a4565b611267565b6103a86112e2565b61033c6103ee366004615270565b6113c7565b61033c6115e4565b6001546102c6906001600160a01b031681565b61029d6118b0565b60085461033c9060ff1681565b61045f6040518060400160405280601e81526020017f436f6d706f756e642d4c657665726167652d53747261746567792d554e49000081525081565b6040516102819190615940565b61029d61047a366004615605565b61196c565b61029d611ba1565b6102c67f000000000000000000000000000000000000000000000000000000000000000081565b6002546102c6906001600160a01b031681565b61027760055481565b61029d6104d836600461516c565b611c4b565b61029d6104eb36600461516c565b611f6a565b61029d6104fe3660046154af565b612133565b610277612207565b61029d61051936600461516c565b61229b565b61027760095481565b610277612536565b6000546102c6906001600160a01b031681565b60085461033c90610100900460ff1681565b61027760075481565b61027761056b3660046155a6565b90565b61029d61057c366004615605565b6125f8565b6000546001600160a01b03166102c6565b61045f6040518060400160405280600681526020016519971817189960d11b81525081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561061057600080fd5b505afa158015610624573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106489190615188565b6001600160a01b0316336001600160a01b0316146106815760405162461bcd60e51b815260040161067890615983565b60405180910390fd5b600154604051631484968760e11b81526001600160a01b038381166004830152909116906329092d0e90602401602060405180830381600087803b1580156106c857600080fd5b505af11580156106dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070091906154cb565b6107435760405162461bcd60e51b81526020600482015260146024820152731c995b5bdd994b5ad9595c195c8b59985a5b195960621b6044820152606401610678565b50565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561079f57600080fd5b505afa1580156107b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d79190615188565b6001600160a01b0316336001600160a01b0316146108075760405162461bcd60e51b815260040161067890615983565b6001546001600160a01b0316156108605760405162461bcd60e51b815260206004820152601b60248201527f6b65657065722d6c6973742d616c72656164792d6372656174656400000000006044820152606401610678565b6000819050806001600160a01b0316630fab4d256040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156108a057600080fd5b505af11580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d89190615188565b600180546001600160a01b0319166001600160a01b03929092169182179055630a3b0a4f6109033390565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381600087803b15801561094457600080fd5b505af1158015610958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097c91906154cb565b6109bc5760405162461bcd60e51b81526020600482015260116024820152701859190b5ad9595c195c8b59985a5b1959607a1b6044820152606401610678565b5050565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614610a345760405162461bcd60e51b815260206004820152601960248201527818d85b1b195c8b5a5ccb5b9bdd0b5d995cdc195c8b5c1bdbdb603a1b6044820152606401610678565b61074381612764565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610a9657600080fd5b505afa158015610aaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ace9190615188565b6001600160a01b0316336001600160a01b031614610afe5760405162461bcd60e51b815260040161067890615983565b600154604051630a3b0a4f60e01b81526001600160a01b03838116600483015290911690630a3b0a4f90602401602060405180830381600087803b158015610b4557600080fd5b505af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d91906154cb565b6107435760405162461bcd60e51b81526020600482015260116024820152701859190b5ad9595c195c8b59985a5b1959607a1b6044820152606401610678565b600b546000906001600160a01b0383811691161480610bf857506001600160a01b03821673c00e94cb662c3520282e6f5717214004a7f26888145b80610c3457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316145b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610c9357600080fd5b505afa158015610ca7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccb9190615188565b6001600160a01b0316336001600160a01b031614610cfb5760405162461bcd60e51b815260040161067890615983565b6001600160a01b038116610d465760405162461bcd60e51b8152602060048201526012602482015271736d2d616464726573732d69732d7a65726f60701b6044820152606401610678565b6003546001600160a01b0382811691161415610d915760405162461bcd60e51b815260206004820152600a602482015269736d2d69732d73616d6560b01b6044820152606401610678565b6003546040516001600160a01b038084169216907f2d19927e7cac08ceb98b38898a4fdff6da6a27295b9a2d62fe250408ebe044e190600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4657600080fd5b505afa158015610e5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7e9190615188565b6001600160a01b0316336001600160a01b031614610eae5760405162461bcd60e51b815260040161067890615983565b610743817f0000000000000000000000000000000000000000000000000000000000000000612791565b6000806000610ee5611063565b9150915080600014610f0d5781610efe61271083615aab565b610f089190615a8b565b610f10565b60005b9250505090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610f7057600080fd5b505afa158015610f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa89190615188565b6001600160a01b0316336001600160a01b031614610fd85760405162461bcd60e51b815260040161067890615983565b6127108111156110235760405162461bcd60e51b8152602060048201526016602482015275696e76616c69642d736c6970706167652d76616c756560501b6044820152606401610678565b60065460408051918252602082018390527ef1c5db862c7598b3b6765552ca951f498611e06412c2d57f8d0b58f82e7f82910160405180910390a1600655565b600b546040516361bfb47160e11b815230600482015260009182918291829182916001600160a01b03169063c37f68e29060240160806040518083038186803b1580156110af57600080fd5b505afa1580156110c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e79190615626565b93509350935050670de0b6b3a764000081846111039190615aab565b61110d9190615a8b565b959194509092505050565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b15801561116957600080fd5b505afa15801561117d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a191906154cb565b6111bd5760405162461bcd60e51b815260040161067890615953565b60008060006111ca6127d4565b6040516302df682360e11b815260048101849052602481018390526044810182905292955090935091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906305bed04690606401600060405180830381600087803b15801561124257600080fd5b505af1158015611256573d6000803e3d6000fd5b50505050611262612bba565b505050565b6000808280602001905181019061127e9190615529565b909250905033731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e146112d15760405162461bcd60e51b81526020600482015260086024820152674e4f545f534f4c4f60c01b6044820152606401610678565b6112db8282612d3e565b5050505050565b600b54604051638e8f294b60e01b81526001600160a01b03909116600482015260009081908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9060240160606040518083038186803b15801561134057600080fd5b505afa158015611354573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137891906154e7565b50915050670de0b6b3a7640000816009546113939190615aab565b61139d9190615a8b565b9250670de0b6b3a764000081600a546113b69190615aab565b6113c09190615a8b565b9150509091565b600073b53c1a33016b2dc2ff3653530bff1848a515c8c56001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561141657600080fd5b505afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190615188565b6001600160a01b0316336001600160a01b03161461149b5760405162461bcd60e51b815260206004820152600a6024820152690858585d994b5c1bdbdb60b21b6044820152606401610678565b60085462010000900460ff166114e85760405162461bcd60e51b815260206004820152601260248201527134b73b30b634b216b33630b9b416b637b0b760711b6044820152606401610678565b6001600160a01b03841630146115345760405162461bcd60e51b815260206004820152601160248201527034b73b30b634b216b4b734ba34b0ba37b960791b6044820152606401610678565b60008686600081811061155757634e487b7160e01b600052603260045260246000fd5b905060200201358989600081811061157f57634e487b7160e01b600052603260045260246000fd5b905060200201356115909190615a73565b90506115d384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250859250612d3e915050565b5060019a9950505050505050505050565b60006115ee612e64565b6003546040516370a0823160e01b81523060048201526000916001600160a01b03169063e8f983c89073c00e94cb662c3520282e6f5717214004a7f26888907f00000000000000000000000000000000000000000000000000000000000000009082906370a082319060240160206040518083038186803b15801561167257600080fd5b505afa158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa91906155be565b6040516001600160e01b031960e086901b1681526001600160a01b039384166004820152929091166024830152604482015260640160006040518083038186803b1580156116f757600080fd5b505afa15801561170b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611733919081019061536d565b50604051639f2b283360e01b8152306004820152909250600091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639f2b28339060240160206040518083038186803b15801561179a57600080fd5b505afa1580156117ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d291906155be565b90506000806117df611063565b6040516370a0823160e01b815230600482015291935091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561184657600080fd5b505afa15801561185a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187e91906155be565b90506000828461188e8885615a73565b6118989190615a73565b6118a29190615aca565b949094109550505050505090565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193991906154cb565b6119555760405162461bcd60e51b815260040161067890615953565b61195f6000612f32565b61196a600019612f32565b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b1580156119c557600080fd5b505afa1580156119d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119fd9190615188565b6001600160a01b0316336001600160a01b031614611a2d5760405162461bcd60e51b815260040161067890615983565b600360009054906101000a90046001600160a01b03166001600160a01b031663c2fba6676040518163ffffffff1660e01b815260040160206040518083038186803b158015611a7b57600080fd5b505afa158015611a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab391906155be565b8110611af85760405162461bcd60e51b81526020600482015260146024820152730d2dcecc2d8d2c85ae4deeae8cae45ad2dcc8caf60631b6044820152606401610678565b81611b035760045491505b603b8211611b4b5760405162461bcd60e51b81526020600482015260156024820152741a5b9d985b1a590b5bdc9858db194b5c195c9a5bd9605a1b6044820152606401610678565b6004546005546040805192835260208301859052820152606081018290527f83bc5ab8030537fcf1d29c2334f6d22c26c82dcbe5ff03923d2cff5c692c0a7f9060800160405180910390a1600491909155600555565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b158015611bf257600080fd5b505afa158015611c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2a91906154cb565b611c465760405162461bcd60e51b815260040161067890615953565b61196a565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614611cbf5760405162461bcd60e51b815260206004820152601960248201527818d85b1b195c8b5a5ccb5b9bdd0b5d995cdc195c8b5c1bdbdb603a1b6044820152606401610678565b6001600160a01b038116611d155760405162461bcd60e51b815260206004820152601c60248201527f6e65772d73747261746567792d616464726573732d69732d7a65726f000000006044820152606401610678565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d7857600080fd5b505afa158015611d8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db09190615188565b6001600160a01b031614611dff5760405162461bcd60e51b81526020600482015260166024820152756e6f742d76616c69642d6e65772d737472617465677960501b6044820152606401610678565b611e0881613127565b6000546040516370a0823160e01b8152306004820152611e9c9183916001600160a01b03909116906370a082319060240160206040518083038186803b158015611e5157600080fd5b505afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8991906155be565b6000546001600160a01b031691906131ff565b6040516370a0823160e01b81523060048201526107439082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b158015611f0157600080fd5b505afa158015611f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3991906155be565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906131ff565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611fc357600080fd5b505afa158015611fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffb9190615188565b6001600160a01b0316336001600160a01b03161461202b5760405162461bcd60e51b815260040161067890615983565b6001600160a01b0381166120815760405162461bcd60e51b815260206004820152601d60248201527f6665652d636f6c6c6563746f722d616464726573732d69732d7a65726f0000006044820152606401610678565b6002546001600160a01b03828116911614156120d75760405162461bcd60e51b81526020600482015260156024820152746665652d636f6c6c6563746f722d69732d73616d6560581b6044820152606401610678565b6002546040516001600160a01b038084169216907f0f06062680f9bd68e786e9980d9bb03d73d5620fc3b345e417b6eacb310b970690600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561218c57600080fd5b505afa1580156121a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c49190615188565b6001600160a01b0316336001600160a01b0316146121f45760405162461bcd60e51b815260040161067890615983565b6008805460ff1916821515179055610743565b60405163331faf7160e21b815230600482015260009061229690733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063cc7ebdc4906024015b60206040518083038186803b15801561225957600080fd5b505afa15801561226d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229191906155be565b613262565b905090565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b1580156122ec57600080fd5b505afa158015612300573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232491906154cb565b6123405760405162461bcd60e51b815260040161067890615953565b6002546001600160a01b03166123905760405162461bcd60e51b81526020600482015260156024820152741999594b58dbdb1b1958dd1bdc8b5b9bdd0b5cd95d605a1b6044820152606401610678565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614156124125760405162461bcd60e51b815260206004820152601f60248201527f6e6f742d616c6c6f7765642d746f2d73776565702d636f6c6c61746572616c006044820152606401610678565b61241b81610bbd565b1561245f5760405162461bcd60e51b815260206004820152601460248201527306e6f742d616c6c6f7765642d746f2d73776565760641b6044820152606401610678565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561249f5760025461249a906001600160a01b031647613404565b610743565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156124e157600080fd5b505afa1580156124f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251991906155be565b6002549091506109bc906001600160a01b038481169116836131ff565b600b546040805163bd6d894d60e01b815290516000926001600160a01b03169163bd6d894d91600480830192602092919082900301818787803b15801561257c57600080fd5b505af1158015612590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b491906155be565b506125bd612e64565b6040516370a0823160e01b81523060048201526122969073c00e94cb662c3520282e6f5717214004a7f26888906370a0823190602401612241565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561265157600080fd5b505afa158015612665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126899190615188565b6001600160a01b0316336001600160a01b0316146126b95760405162461bcd60e51b815260040161067890615983565b612710811061270a5760405162461bcd60e51b815260206004820152601860248201527f696e76616c69642d6d61782d626f72726f772d6c696d697400000000000000006044820152606401610678565b8181116127595760405162461bcd60e51b815260206004820152601d60248201527f6d61782d73686f756c642d62652d6869676865722d7468616e2d6d696e0000006044820152606401610678565b600991909155600a55565b6107437f0000000000000000000000000000000000000000000000000000000000000000611f398361351d565b81156127b9576127b5731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e82613984565b6007555b50600880549115156101000261ff0019909216919091179055565b604051636a9eee1360e11b81523060048201526000908190819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d53ddc269060240160206040518083038186803b15801561283c57600080fd5b505afa158015612850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287491906155be565b604051639f2b283360e01b81523060048201529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639f2b28339060240160206040518083038186803b1580156128d957600080fd5b505afa1580156128ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291191906155be565b905061293c7f0000000000000000000000000000000000000000000000000000000000000000613b05565b600b54604051633af9e66960e01b81523060048201526000916001600160a01b031690633af9e66990602401602060405180830381600087803b15801561298257600080fd5b505af1158015612996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ba91906155be565b600b546040516395dd919360e01b81523060048201529192506000916001600160a01b03909116906395dd91939060240160206040518083038186803b158015612a0357600080fd5b505afa158015612a17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a3b91906155be565b90506000612a498284615aca565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b158015612aae57600080fd5b505afa158015612ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae691906155be565b90506000612af48284615a73565b9050600086821115612b4e57612b0a8783615aca565b9a508a8311612b2457612b1d838c615aca565b9050612b49565b612b2e888c615a73565b8310612b3c57879850612b49565b612b468b84615aca565b98505b612b5b565b612b588288615aca565b99505b6000612b678a8a615aca565b90506000612b758383615a73565b90508015612bab576000612b888261351d565b905083811115612ba957612b9c8482615aca565b612ba6908d615a73565b9b505b505b50505050505050505050909192565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612c1c57600080fd5b505afa158015612c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5491906155be565b9050600080612c64836001613bb9565b91509150612c7183613db2565b600854610100900460ff168015612c885750600082115b15612cf75760008282604051602001612cad9291909182521515602082015260400190565b6040516020818303038152906040529050612ce97f00000000000000000000000000000000000000000000000000000000000000008483613e7d565b612cf39084615aca565b9250505b60005b600083118015612d0b575060068111155b15612d3857612d1a8383614188565b612d249084615aca565b925080612d3081615b0d565b915050612cfa565b50505050565b60008083806020019051810190612d5591906155d6565b6040516370a0823160e01b815230600482015291935091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b158015612dbc57600080fd5b505afa158015612dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df491906155be565b905082811015612e355760405162461bcd60e51b815260206004820152600c60248201526b11931054d217d1905253115160a21b6044820152606401610678565b8115612e5257612e448361427d565b612e4d84614348565b6112db565b612e5b81613db2565b6112db84614413565b604080516001808252818301909252600091602080830190803683375050600b5482519293506001600160a01b031691839150600090612eb457634e487b7160e01b600052603260045260246000fd5b6001600160a01b039092166020928302919091019091015260405162e1ed9760e51b8152733d9819210a31b4961b30ef54be2aed79b9c9cd3b90631c3db2e090612f04903090859060040161574c565b600060405180830381600087803b158015612f1e57600080fd5b505af11580156112db573d6000803e3d6000fd5b612f866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000836144de565b600b54612fc0906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836144de565b60005b600360009054906101000a90046001600160a01b03166001600160a01b031663c2fba6676040518163ffffffff1660e01b815260040160206040518083038186803b15801561301157600080fd5b505afa158015613025573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304991906155be565b8110156130fc57600354604051636e74a6f760e01b8152600481018390526130ea916001600160a01b031690636e74a6f79060240160206040518083038186803b15801561309657600080fd5b505afa1580156130aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ce9190615188565b73c00e94cb662c3520282e6f5717214004a7f2688890846144de565b806130f481615b0d565b915050612fc3565b506107437f000000000000000000000000000000000000000000000000000000000000000082614602565b600b5460408051637e062a3560e11b815290516001600160a01b039283169284169163fc0c546a916004808301926020929190829003018186803b15801561316e57600080fd5b505afa158015613182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a69190615188565b6001600160a01b0316146131f25760405162461bcd60e51b81526020600482015260136024820152723bb937b73396b932b1b2b4b83a16ba37b5b2b760691b6044820152606401610678565b6000600955610743612bba565b6040516001600160a01b03831660248201526044810182905261126290849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526146c3565b600080821561333257600354604051631d1f307960e31b815273c00e94cb662c3520282e6f5717214004a7f2688860048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018690529091169063e8f983c89060640160006040518083038186803b1580156132f157600080fd5b505afa158015613305573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261332d919081019061536d565b509150505b60008061333d611063565b6040516370a0823160e01b81523060048201529193509150819083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b1580156133a557600080fd5b505afa1580156133b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133dd91906155be565b6133e79086615a73565b6133f19190615a73565b6133fb9190615aca565b95945050505050565b804710156134545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610678565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146134a1576040519150601f19603f3d011682016040523d82523d6000602084013e6134a6565b606091505b50509050806112625760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610678565b600080600061352d846000613bb9565b9150915080156136dc57600854610100900460ff16156135b157600082826040516020016135679291909182521515602082015260400190565b60405160208183030381529060405290506135a37f00000000000000000000000000000000000000000000000000000000000000008483613e7d565b6135ad9084615aca565b9250505b6000821180156135c3575060085460ff165b1561363257600082826040516020016135e89291909182521515602082015260400190565b60405160208183030381529060405290506136247f00000000000000000000000000000000000000000000000000000000000000008483614795565b61362e9084615aca565b9250505b60005b6000831180156136465750600a8111155b1561367457613656836001614188565b6136609084615aca565b92508061366c81615b0d565b915050613635565b82156136da57600080613685611063565b9150915060006136936112e2565b9150506000816000146136ba57816136ad61271085615aab565b6136b79190615a8b565b90505b60006136c68286615aca565b9050808a11156136d4578099505b50505050505b505b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561373e57600080fd5b505afa158015613752573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377691906155be565b600b54604051633af9e66960e01b81523060048201529192506001600160a01b031690633af9e66990602401602060405180830381600087803b1580156137bc57600080fd5b505af11580156137d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f491906155be565b8511156138cb575060006138277f0000000000000000000000000000000000000000000000000000000000000000613b05565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561388657600080fd5b505afa15801561389a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138be91906155be565b6138c89086615aca565b94505b6138d485614348565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561393657600080fd5b505afa15801561394a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396e91906155be565b905061397a8282615aca565b9695505050505050565b6000808390506000816001600160a01b031663295c39a56040518163ffffffff1660e01b815260040160206040518083038186803b1580156139c557600080fd5b505afa1580156139d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139fd91906155be565b90506000805b82811015613abc5760405163062bd3e960e01b8152600481018290526001600160a01b0385169063062bd3e99060240160206040518083038186803b158015613a4b57600080fd5b505afa158015613a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a839190615188565b9150856001600160a01b0316826001600160a01b03161415613aaa579350610c3492505050565b80613ab481615b0d565b915050613a03565b5060405162461bcd60e51b815260206004820152601b60248201527f6e6f2d6d61726b657449642d666f756e642d666f722d746f6b656e00000000006044820152606401610678565b613b0d612e64565b6040516370a0823160e01b815230600482015260009073c00e94cb662c3520282e6f5717214004a7f26888906370a082319060240160206040518083038186803b158015613b5a57600080fd5b505afa158015613b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9291906155be565b905080156109bc576109bc73c00e94cb662c3520282e6f5717214004a7f268888383614a09565b600b54604051633af9e66960e01b8152306004820152600091829182916001600160a01b031690633af9e66990602401602060405180830381600087803b158015613c0357600080fd5b505af1158015613c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3b91906155be565b600b546040516395dd919360e01b81523060048201529192506000916001600160a01b03909116906395dd91939060240160206040518083038186803b158015613c8457600080fd5b505afa158015613c98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbc91906155be565b905060095460001415613cd657925060019150613dab9050565b6000613ce28284615aca565b9050600086613d0857878211613cf9576000613d03565b613d038883615aca565b613d12565b613d128883615a73565b9050600080613d1f6112e2565b90925090506000613d3282612710615aca565b613d3c8386615aab565b613d469190615a8b565b90506000613d5684612710615aca565b613d608587615aab565b613d6a9190615a8b565b905081871115613d895760019850613d828188615aca565b9950613da2565b80871015613da25760009850613d9f8782615aca565b99505b50505050505050505b9250929050565b600b5460405163140e25ad60e31b8152600481018390526001600160a01b039091169063a0712d6890602401602060405180830381600087803b158015613df857600080fd5b505af1158015613e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e3091906155be565b156107435760405162461bcd60e51b815260206004820152601960248201527f737570706c792d746f2d636f6d706f756e642d6661696c6564000000000000006044820152606401610678565b600854600090610100900460ff16613ed75760405162461bcd60e51b815260206004820152601d60248201527f647964782d666c6173682d6c6f616e2d69732d6e6f742d6163746976650000006044820152606401610678565b506040516370a0823160e01b8152731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e600482015282906000906001600160a01b038616906370a082319060240160206040518083038186803b158015613f3057600080fd5b505afa158015613f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f6891906155be565b905080821115613f76578091505b6000613f83836002615a73565b905060008482604051602001613f9a92919061591e565b60408051808303601f19018152600380845260808401909252925060009190816020015b613fc66150b3565b815260200190600190039081613fbe579050509050613fe760075486614ada565b8160008151811061400857634e487b7160e01b600052603260045260246000fd5b602002602001018190525061401c82614b64565b8160018151811061403d57634e487b7160e01b600052603260045260246000fd5b602002602001018190525061405460075484614bd2565b8160028151811061407557634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081614097575050604080518082018252600080825260209182015281518083019092523082526001908201529091508160008151811061410657634e487b7160e01b600052603260045260246000fd5b602090810291909101015260405163a67a6a4560e01b8152731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e9063a67a6a459061414a90849086906004016157ee565b600060405180830381600087803b15801561416457600080fd5b505af1158015614178573d6000803e3d6000fd5b5050505050505050509392505050565b6000806000614195611063565b915091508060001480156141a65750835b156141b657600092505050610c34565b600b54604051638e8f294b60e01b81526001600160a01b039091166004820152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9060240160606040518083038186803b15801561421057600080fd5b505afa158015614224573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424891906154e7565b5091505084156142655761425e86848484614c0d565b9350614274565b61427186848484614c73565b93505b50505092915050565b600b5460405163073a938160e11b8152600481018390526001600160a01b0390911690630e75270290602401602060405180830381600087803b1580156142c357600080fd5b505af11580156142d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142fb91906155be565b156107435760405162461bcd60e51b815260206004820152601860248201527f72657061792d746f2d636f6d706f756e642d6661696c656400000000000000006044820152606401610678565b600b5460405163852a12e360e01b8152600481018390526001600160a01b039091169063852a12e390602401602060405180830381600087803b15801561438e57600080fd5b505af11580156143a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c691906155be565b156107435760405162461bcd60e51b815260206004820152601d60248201527f77697468647261772d66726f6d2d636f6d706f756e642d6661696c65640000006044820152606401610678565b600b5460405163317afabb60e21b8152600481018390526001600160a01b039091169063c5ebeaec90602401602060405180830381600087803b15801561445957600080fd5b505af115801561446d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061449191906155be565b156107435760405162461bcd60e51b815260206004820152601b60248201527f626f72726f772d66726f6d2d636f6d706f756e642d6661696c656400000000006044820152606401610678565b8015806145675750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561452d57600080fd5b505afa158015614541573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061456591906155be565b155b6145d25760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610678565b6040516001600160a01b03831660248201526044810182905261126290849063095ea7b360e01b9060640161322b565b61462a6001600160a01b038316731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e836144de565b6109bc73b53c1a33016b2dc2ff3653530bff1848a515c8c56001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561467a57600080fd5b505afa15801561468e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146b29190615188565b6001600160a01b03841690836144de565b6000614718826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614d559092919063ffffffff16565b805190915015611262578080602001905181019061473691906154cb565b6112625760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610678565b60085460009060ff166147ea5760405162461bcd60e51b815260206004820152601d60248201527f616176652d666c6173682d6c6f616e2d69732d6e6f742d6163746976650000006044820152606401610678565b600073b53c1a33016b2dc2ff3653530bff1848a515c8c56001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561483957600080fd5b505afa15801561484d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148719190615188565b604080516001808252818301909252919250600091906020808301908036833701905050905085816000815181106148b957634e487b7160e01b600052603260045260246000fd5b6001600160a01b039290921660209283029190910190910152604080516001808252818301909252600091816020016020820280368337019050509050858160008151811061491857634e487b7160e01b600052603260045260246000fd5b602090810291909101015260408051600180825281830190925260009181602001602082028036833701905050905060008160008151811061496a57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526008805462ff000019166201000017905560405163ab9c4b5d60e01b81526001600160a01b0385169063ab9c4b5d906149bf90309087908790879084908e90600090600401615770565b600060405180830381600087803b1580156149d957600080fd5b505af11580156149ed573d6000803e3d6000fd5b50506008805462ff000019169055509698975050505050505050565b60006006546127101415614a1e576001614acc565b6040516358fac00360e01b81526001600160a01b0380861660048301526024820184905284166044820152610e106064820152614acc90730f1f5a87f99f0918e6c81f16e59f3518698221ff906358fac0039060840160206040518083038186803b158015614a8c57600080fd5b505afa158015614aa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ac491906155be565b600654614d6e565b9050612d3884848484614d91565b614ae26150b3565b604080516101008101825260018152600060208083018290528351608081018552828152929384019291908201905b81526020016000815260200185815250815260200184815260200160008152602001306001600160a01b031681526020016000815260200160405180602001604052806000815250815250905092915050565b614b6c6150b3565b6040805161010081018252600881526000602080830182905283516080810185528281529293840192919082019081526020016000815260006020918201819052918352820181905260408201819052306060830152608082015260a001929092525090565b614bda6150b3565b60408051610100810182526000808252602080830182905283516080810185526001815292938401929190820190614b11565b6000808215614c365782614c2985670de0b6b3a7640000615aab565b614c339190615a8b565b90505b614c408186615aca565b9150838210614c4d578391505b858210614c58578591505b614c6182614348565b614c6a8261427d565b50949350505050565b600080670de0b6b3a7640000614c898487615aab565b614c939190615a8b565b9050614c9f8482615aca565b9150858210614cac578591505b614cb582614413565b6040516370a0823160e01b8152306004820152614c6a907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015614d1857600080fd5b505afa158015614d2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d5091906155be565b613db2565b6060614d648484600085614f52565b90505b9392505050565b6000612710614d7d8382615aca565b614d879085615aab565b614d679190615a8b565b600354604051631d1f307960e31b81526001600160a01b038681166004830152858116602483015260448201859052600092839283929091169063e8f983c89060640160006040518083038186803b158015614dec57600080fd5b505afa158015614e00573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052614e28919081019061536d565b9250925092508360001415614e3c57600193505b8115614f4957600354604051636e74a6f760e01b8152600481018390526001600160a01b0390911690636e74a6f79060240160206040518083038186803b158015614e8657600080fd5b505afa158015614e9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ebe9190615188565b6001600160a01b03166338ed173986868630426040518663ffffffff1660e01b8152600401614ef19594939291906159ba565b600060405180830381600087803b158015614f0b57600080fd5b505af1158015614f1f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052614f47919081019061541c565b505b50505050505050565b606082471015614fb35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610678565b843b6150015760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610678565b600080866001600160a01b0316858760405161501d9190615730565b60006040518083038185875af1925050503d806000811461505a576040519150601f19603f3d011682016040523d82523d6000602084013e61505f565b606091505b509150915061506f82828661507a565b979650505050505050565b60608315615089575081614d67565b8251156150995782518084602001fd5b8160405162461bcd60e51b81526004016106789190615940565b6040805161010081018252600080825260208201529081016150f7604080516080810190915260008082526020820190815260200160008152602001600081525090565b8152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b60008083601f84011261513a578182fd5b50813567ffffffffffffffff811115615151578182fd5b6020830191508360208260051b8501011115613dab57600080fd5b60006020828403121561517d578081fd5b8135614d6781615b7a565b600060208284031215615199578081fd5b8151614d6781615b7a565b600080600083850360808112156151b9578283fd5b84356151c481615b7a565b935060206040601f19830112156151d9578384fd5b6151e360406159f6565b9150808601356151f281615b7a565b825260408601358183015290925060608501359067ffffffffffffffff82111561521a578283fd5b818601915086601f83011261522d578283fd5b813561524061523b82615a4b565b6159f6565b8181528883838601011115615253578485fd5b818385018483013784838383010152809450505050509250925092565b600080600080600080600080600060a08a8c03121561528d578485fd5b893567ffffffffffffffff808211156152a4578687fd5b6152b08d838e01615129565b909b50995060208c01359150808211156152c8578687fd5b6152d48d838e01615129565b909950975060408c01359150808211156152ec578687fd5b6152f88d838e01615129565b909750955060608c0135915061530d82615b7a565b90935060808b01359080821115615322578384fd5b818c0191508c601f830112615335578384fd5b813581811115615343578485fd5b8d6020828501011115615354578485fd5b6020830194508093505050509295985092959850929598565b600080600060608486031215615381578283fd5b835167ffffffffffffffff811115615397578384fd5b8401601f810186136153a7578384fd5b805160206153b761523b83615a27565b8083825282820191508285018a848660051b88010111156153d6578889fd5b8895505b848610156154015780516153ed81615b7a565b8352600195909501949183019183016153da565b50918801516040909801519199979850909695505050505050565b6000602080838503121561542e578182fd5b825167ffffffffffffffff811115615444578283fd5b8301601f81018513615454578283fd5b805161546261523b82615a27565b80828252848201915084840188868560051b8701011115615481578687fd5b8694505b838510156154a3578051835260019490940193918501918501615485565b50979650505050505050565b6000602082840312156154c0578081fd5b8135614d6781615b8f565b6000602082840312156154dc578081fd5b8151614d6781615b8f565b6000806000606084860312156154fb578081fd5b835161550681615b8f565b60208501516040860151919450925061551e81615b8f565b809150509250925092565b6000806040838503121561553b578182fd5b825167ffffffffffffffff811115615551578283fd5b8301601f81018513615561578283fd5b805161556f61523b82615a4b565b818152866020838501011115615583578485fd5b615594826020830160208601615ae1565b60209590950151949694955050505050565b6000602082840312156155b7578081fd5b5035919050565b6000602082840312156155cf578081fd5b5051919050565b600080604083850312156155e8578182fd5b8251915060208301516155fa81615b8f565b809150509250929050565b60008060408385031215615617578182fd5b50508035926020909101359150565b6000806000806080858703121561563b578182fd5b505082516020840151604085015160609095015191969095509092509050565b6000815180845260208085019450808401835b838110156156935781516001600160a01b03168752958201959082019060010161566e565b509495945050505050565b6000815180845260208085019450808401835b83811015615693578151875295820195908201906001016156b1565b600081518084526156e5816020860160208601615ae1565b601f01601f19169290920160200192915050565b805115158252602081015161570d81615b6a565b6020830152604081015161572081615b6a565b6040830152606090810151910152565b60008251615742818460208701615ae1565b9190910192915050565b6001600160a01b0383168152604060208201819052600090614d649083018461565b565b600060018060a01b03808a16835260e0602084015261579260e084018a61565b565b83810360408501526157a4818a61569e565b905083810360608501526157b8818961569e565b9050818716608085015283810360a08501526157d481876156cd565b9250505061ffff831660c083015298975050505050505050565b6040808252835182820181905260009190606090818501906020808901865b8381101561583b57815180516001600160a01b0316865283015183860152938601939082019060010161580d565b50508683038188015287518084528184019250600581901b84018201898301885b8381101561590d57601f19878403018652815161016081516009811061588457615884615b3e565b855281870151878601528a82015161589e8c8701826156f9565b508982015160c081818801526080840151915060e0828189015260a085015192506158d56101008901846001600160a01b03169052565b9084015161012088015290920151610140860182905291506158f9818601836156cd565b97870197945050509084019060010161585c565b50909b9a5050505050505050505050565b60006040825261593160408301856156cd565b90508260208301529392505050565b600060208252614d6760208301846156cd565b60208082526016908201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b604082015260600190565b6020808252601a908201527f63616c6c65722d69732d6e6f742d7468652d676f7665726e6f72000000000000604082015260600190565b600086825285602083015260a060408301526159d960a083018661565b565b6001600160a01b0394909416606083015250608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715615a1f57615a1f615b54565b604052919050565b600067ffffffffffffffff821115615a4157615a41615b54565b5060051b60200190565b600067ffffffffffffffff821115615a6557615a65615b54565b50601f01601f191660200190565b60008219821115615a8657615a86615b28565b500190565b600082615aa657634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615ac557615ac5615b28565b500290565b600082821015615adc57615adc615b28565b500390565b60005b83811015615afc578181015183820152602001615ae4565b83811115612d385750506000910152565b6000600019821415615b2157615b21615b28565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6002811061074357610743615b3e565b6001600160a01b038116811461074357600080fd5b801515811461074357600080fdfea2646970667358221220a62e284941a615045dec466ea4ca927f82f95e987ed2d8f21a4f991d746beaa064736f6c63430008030033000000000000000000000000ff43c327410f960261057ba1da787ed78b42c257000000000000000000000000e382d9f2394a359b01006faa8a1864b8a60d2710
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102695760003560e01c806399b71d5c11610151578063d4c3eea0116100c3578063f23c472211610087578063f23c472214610542578063f7c99bea14610554578063fb589de21461055d578063fb7ee1021461056e578063fc0c546a14610581578063ffa1ad741461059257610269565b8063d4c3eea014610503578063e00af4a71461050b578063e260d7471461051e578063e645c20214610527578063ec78e8321461052f57610269565b8063b2016bd411610115578063b2016bd414610487578063c415b95c146104ae578063cd2d7ebe146104c1578063ce5494bb146104ca578063d2c35ce8146104dd578063d3332539146104f057610269565b806399b71d5c1461040e5780639b7166a914610416578063a3f4df7e14610423578063a923b2a61461046c578063aa1018861461047f57610269565b8063599e892a116101ea5780637d7c2a1c116101ae5780637d7c2a1c146103bd5780638b418713146103c557806391d260e9146103d8578063920f5c84146103e057806392986024146103f3578063951dc22c146103fb57610269565b8063599e892a1461035f5780635abda0281461037257806367f5e4b81461037a578063709d039d1461038d5780637398ab18146103a057610269565b80632e1a7d4d116102315780632e1a7d4d146102fa5780634032b72b1461030d57806342189c8f14610320578063440d7248146103295780634c36fad71461034c57610269565b80630181686c1461026e57806314ae9f2e1461028a57806316f0115b1461029f57806319ab453c146102de5780631aedeabe146102f1575b600080fd5b610277600a5481565b6040519081526020015b60405180910390f35b61029d61029836600461516c565b6105b7565b005b6102c67f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c25781565b6040516001600160a01b039091168152602001610281565b61029d6102ec36600461516c565b610746565b61027760065481565b61029d6103083660046155a6565b6109c0565b61029d61031b36600461516c565b610a3d565b61027760045481565b61033c61033736600461516c565b610bbd565b6040519015158152602001610281565b61029d61035a36600461516c565b610c3a565b61029d61036d3660046154af565b610ded565b610277610ed8565b61029d6103883660046155a6565b610f17565b6003546102c6906001600160a01b031681565b6103a8611063565b60408051928352602083019190915201610281565b61029d611118565b61029d6103d33660046151a4565b611267565b6103a86112e2565b61033c6103ee366004615270565b6113c7565b61033c6115e4565b6001546102c6906001600160a01b031681565b61029d6118b0565b60085461033c9060ff1681565b61045f6040518060400160405280601e81526020017f436f6d706f756e642d4c657665726167652d53747261746567792d554e49000081525081565b6040516102819190615940565b61029d61047a366004615605565b61196c565b61029d611ba1565b6102c67f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98481565b6002546102c6906001600160a01b031681565b61027760055481565b61029d6104d836600461516c565b611c4b565b61029d6104eb36600461516c565b611f6a565b61029d6104fe3660046154af565b612133565b610277612207565b61029d61051936600461516c565b61229b565b61027760095481565b610277612536565b6000546102c6906001600160a01b031681565b60085461033c90610100900460ff1681565b61027760075481565b61027761056b3660046155a6565b90565b61029d61057c366004615605565b6125f8565b6000546001600160a01b03166102c6565b61045f6040518060400160405280600681526020016519971817189960d11b81525081565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561061057600080fd5b505afa158015610624573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106489190615188565b6001600160a01b0316336001600160a01b0316146106815760405162461bcd60e51b815260040161067890615983565b60405180910390fd5b600154604051631484968760e11b81526001600160a01b038381166004830152909116906329092d0e90602401602060405180830381600087803b1580156106c857600080fd5b505af11580156106dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070091906154cb565b6107435760405162461bcd60e51b81526020600482015260146024820152731c995b5bdd994b5ad9595c195c8b59985a5b195960621b6044820152606401610678565b50565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561079f57600080fd5b505afa1580156107b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d79190615188565b6001600160a01b0316336001600160a01b0316146108075760405162461bcd60e51b815260040161067890615983565b6001546001600160a01b0316156108605760405162461bcd60e51b815260206004820152601b60248201527f6b65657065722d6c6973742d616c72656164792d6372656174656400000000006044820152606401610678565b6000819050806001600160a01b0316630fab4d256040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156108a057600080fd5b505af11580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d89190615188565b600180546001600160a01b0319166001600160a01b03929092169182179055630a3b0a4f6109033390565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381600087803b15801561094457600080fd5b505af1158015610958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097c91906154cb565b6109bc5760405162461bcd60e51b81526020600482015260116024820152701859190b5ad9595c195c8b59985a5b1959607a1b6044820152606401610678565b5050565b337f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b031614610a345760405162461bcd60e51b815260206004820152601960248201527818d85b1b195c8b5a5ccb5b9bdd0b5d995cdc195c8b5c1bdbdb603a1b6044820152606401610678565b61074381612764565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610a9657600080fd5b505afa158015610aaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ace9190615188565b6001600160a01b0316336001600160a01b031614610afe5760405162461bcd60e51b815260040161067890615983565b600154604051630a3b0a4f60e01b81526001600160a01b03838116600483015290911690630a3b0a4f90602401602060405180830381600087803b158015610b4557600080fd5b505af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d91906154cb565b6107435760405162461bcd60e51b81526020600482015260116024820152701859190b5ad9595c195c8b59985a5b1959607a1b6044820152606401610678565b600b546000906001600160a01b0383811691161480610bf857506001600160a01b03821673c00e94cb662c3520282e6f5717214004a7f26888145b80610c3457507f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0316826001600160a01b0316145b92915050565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610c9357600080fd5b505afa158015610ca7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccb9190615188565b6001600160a01b0316336001600160a01b031614610cfb5760405162461bcd60e51b815260040161067890615983565b6001600160a01b038116610d465760405162461bcd60e51b8152602060048201526012602482015271736d2d616464726573732d69732d7a65726f60701b6044820152606401610678565b6003546001600160a01b0382811691161415610d915760405162461bcd60e51b815260206004820152600a602482015269736d2d69732d73616d6560b01b6044820152606401610678565b6003546040516001600160a01b038084169216907f2d19927e7cac08ceb98b38898a4fdff6da6a27295b9a2d62fe250408ebe044e190600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4657600080fd5b505afa158015610e5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7e9190615188565b6001600160a01b0316336001600160a01b031614610eae5760405162461bcd60e51b815260040161067890615983565b610743817f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984612791565b6000806000610ee5611063565b9150915080600014610f0d5781610efe61271083615aab565b610f089190615a8b565b610f10565b60005b9250505090565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610f7057600080fd5b505afa158015610f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa89190615188565b6001600160a01b0316336001600160a01b031614610fd85760405162461bcd60e51b815260040161067890615983565b6127108111156110235760405162461bcd60e51b8152602060048201526016602482015275696e76616c69642d736c6970706167652d76616c756560501b6044820152606401610678565b60065460408051918252602082018390527ef1c5db862c7598b3b6765552ca951f498611e06412c2d57f8d0b58f82e7f82910160405180910390a1600655565b600b546040516361bfb47160e11b815230600482015260009182918291829182916001600160a01b03169063c37f68e29060240160806040518083038186803b1580156110af57600080fd5b505afa1580156110c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e79190615626565b93509350935050670de0b6b3a764000081846111039190615aab565b61110d9190615a8b565b959194509092505050565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b15801561116957600080fd5b505afa15801561117d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a191906154cb565b6111bd5760405162461bcd60e51b815260040161067890615953565b60008060006111ca6127d4565b6040516302df682360e11b815260048101849052602481018390526044810182905292955090935091506001600160a01b037f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c25716906305bed04690606401600060405180830381600087803b15801561124257600080fd5b505af1158015611256573d6000803e3d6000fd5b50505050611262612bba565b505050565b6000808280602001905181019061127e9190615529565b909250905033731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e146112d15760405162461bcd60e51b81526020600482015260086024820152674e4f545f534f4c4f60c01b6044820152606401610678565b6112db8282612d3e565b5050505050565b600b54604051638e8f294b60e01b81526001600160a01b03909116600482015260009081908190733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9060240160606040518083038186803b15801561134057600080fd5b505afa158015611354573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137891906154e7565b50915050670de0b6b3a7640000816009546113939190615aab565b61139d9190615a8b565b9250670de0b6b3a764000081600a546113b69190615aab565b6113c09190615a8b565b9150509091565b600073b53c1a33016b2dc2ff3653530bff1848a515c8c56001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561141657600080fd5b505afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190615188565b6001600160a01b0316336001600160a01b03161461149b5760405162461bcd60e51b815260206004820152600a6024820152690858585d994b5c1bdbdb60b21b6044820152606401610678565b60085462010000900460ff166114e85760405162461bcd60e51b815260206004820152601260248201527134b73b30b634b216b33630b9b416b637b0b760711b6044820152606401610678565b6001600160a01b03841630146115345760405162461bcd60e51b815260206004820152601160248201527034b73b30b634b216b4b734ba34b0ba37b960791b6044820152606401610678565b60008686600081811061155757634e487b7160e01b600052603260045260246000fd5b905060200201358989600081811061157f57634e487b7160e01b600052603260045260246000fd5b905060200201356115909190615a73565b90506115d384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250859250612d3e915050565b5060019a9950505050505050505050565b60006115ee612e64565b6003546040516370a0823160e01b81523060048201526000916001600160a01b03169063e8f983c89073c00e94cb662c3520282e6f5717214004a7f26888907f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9849082906370a082319060240160206040518083038186803b15801561167257600080fd5b505afa158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa91906155be565b6040516001600160e01b031960e086901b1681526001600160a01b039384166004820152929091166024830152604482015260640160006040518083038186803b1580156116f757600080fd5b505afa15801561170b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611733919081019061536d565b50604051639f2b283360e01b8152306004820152909250600091506001600160a01b037f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2571690639f2b28339060240160206040518083038186803b15801561179a57600080fd5b505afa1580156117ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d291906155be565b90506000806117df611063565b6040516370a0823160e01b815230600482015291935091506000906001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98416906370a082319060240160206040518083038186803b15801561184657600080fd5b505afa15801561185a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187e91906155be565b90506000828461188e8885615a73565b6118989190615a73565b6118a29190615aca565b949094109550505050505090565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b15801561190157600080fd5b505afa158015611915573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193991906154cb565b6119555760405162461bcd60e51b815260040161067890615953565b61195f6000612f32565b61196a600019612f32565b565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b1580156119c557600080fd5b505afa1580156119d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119fd9190615188565b6001600160a01b0316336001600160a01b031614611a2d5760405162461bcd60e51b815260040161067890615983565b600360009054906101000a90046001600160a01b03166001600160a01b031663c2fba6676040518163ffffffff1660e01b815260040160206040518083038186803b158015611a7b57600080fd5b505afa158015611a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab391906155be565b8110611af85760405162461bcd60e51b81526020600482015260146024820152730d2dcecc2d8d2c85ae4deeae8cae45ad2dcc8caf60631b6044820152606401610678565b81611b035760045491505b603b8211611b4b5760405162461bcd60e51b81526020600482015260156024820152741a5b9d985b1a590b5bdc9858db194b5c195c9a5bd9605a1b6044820152606401610678565b6004546005546040805192835260208301859052820152606081018290527f83bc5ab8030537fcf1d29c2334f6d22c26c82dcbe5ff03923d2cff5c692c0a7f9060800160405180910390a1600491909155600555565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b158015611bf257600080fd5b505afa158015611c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2a91906154cb565b611c465760405162461bcd60e51b815260040161067890615953565b61196a565b337f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b031614611cbf5760405162461bcd60e51b815260206004820152601960248201527818d85b1b195c8b5a5ccb5b9bdd0b5d995cdc195c8b5c1bdbdb603a1b6044820152606401610678565b6001600160a01b038116611d155760405162461bcd60e51b815260206004820152601c60248201527f6e65772d73747261746567792d616464726573732d69732d7a65726f000000006044820152606401610678565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d7857600080fd5b505afa158015611d8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db09190615188565b6001600160a01b031614611dff5760405162461bcd60e51b81526020600482015260166024820152756e6f742d76616c69642d6e65772d737472617465677960501b6044820152606401610678565b611e0881613127565b6000546040516370a0823160e01b8152306004820152611e9c9183916001600160a01b03909116906370a082319060240160206040518083038186803b158015611e5157600080fd5b505afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8991906155be565b6000546001600160a01b031691906131ff565b6040516370a0823160e01b81523060048201526107439082906001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98416906370a082319060240160206040518083038186803b158015611f0157600080fd5b505afa158015611f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3991906155be565b6001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9841691906131ff565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611fc357600080fd5b505afa158015611fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffb9190615188565b6001600160a01b0316336001600160a01b03161461202b5760405162461bcd60e51b815260040161067890615983565b6001600160a01b0381166120815760405162461bcd60e51b815260206004820152601d60248201527f6665652d636f6c6c6563746f722d616464726573732d69732d7a65726f0000006044820152606401610678565b6002546001600160a01b03828116911614156120d75760405162461bcd60e51b81526020600482015260156024820152746665652d636f6c6c6563746f722d69732d73616d6560581b6044820152606401610678565b6002546040516001600160a01b038084169216907f0f06062680f9bd68e786e9980d9bb03d73d5620fc3b345e417b6eacb310b970690600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561218c57600080fd5b505afa1580156121a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c49190615188565b6001600160a01b0316336001600160a01b0316146121f45760405162461bcd60e51b815260040161067890615983565b6008805460ff1916821515179055610743565b60405163331faf7160e21b815230600482015260009061229690733d9819210a31b4961b30ef54be2aed79b9c9cd3b9063cc7ebdc4906024015b60206040518083038186803b15801561225957600080fd5b505afa15801561226d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229191906155be565b613262565b905090565b6001546001600160a01b0316635dbe47e8336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b1580156122ec57600080fd5b505afa158015612300573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232491906154cb565b6123405760405162461bcd60e51b815260040161067890615953565b6002546001600160a01b03166123905760405162461bcd60e51b81526020600482015260156024820152741999594b58dbdb1b1958dd1bdc8b5b9bdd0b5cd95d605a1b6044820152606401610678565b7f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0316816001600160a01b031614156124125760405162461bcd60e51b815260206004820152601f60248201527f6e6f742d616c6c6f7765642d746f2d73776565702d636f6c6c61746572616c006044820152606401610678565b61241b81610bbd565b1561245f5760405162461bcd60e51b815260206004820152601460248201527306e6f742d616c6c6f7765642d746f2d73776565760641b6044820152606401610678565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561249f5760025461249a906001600160a01b031647613404565b610743565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b1580156124e157600080fd5b505afa1580156124f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251991906155be565b6002549091506109bc906001600160a01b038481169116836131ff565b600b546040805163bd6d894d60e01b815290516000926001600160a01b03169163bd6d894d91600480830192602092919082900301818787803b15801561257c57600080fd5b505af1158015612590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b491906155be565b506125bd612e64565b6040516370a0823160e01b81523060048201526122969073c00e94cb662c3520282e6f5717214004a7f26888906370a0823190602401612241565b7f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2576001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561265157600080fd5b505afa158015612665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126899190615188565b6001600160a01b0316336001600160a01b0316146126b95760405162461bcd60e51b815260040161067890615983565b612710811061270a5760405162461bcd60e51b815260206004820152601860248201527f696e76616c69642d6d61782d626f72726f772d6c696d697400000000000000006044820152606401610678565b8181116127595760405162461bcd60e51b815260206004820152601d60248201527f6d61782d73686f756c642d62652d6869676865722d7468616e2d6d696e0000006044820152606401610678565b600991909155600a55565b6107437f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c257611f398361351d565b81156127b9576127b5731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e82613984565b6007555b50600880549115156101000261ff0019909216919091179055565b604051636a9eee1360e11b81523060048201526000908190819081906001600160a01b037f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c257169063d53ddc269060240160206040518083038186803b15801561283c57600080fd5b505afa158015612850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287491906155be565b604051639f2b283360e01b81523060048201529091506000906001600160a01b037f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c2571690639f2b28339060240160206040518083038186803b1580156128d957600080fd5b505afa1580156128ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291191906155be565b905061293c7f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984613b05565b600b54604051633af9e66960e01b81523060048201526000916001600160a01b031690633af9e66990602401602060405180830381600087803b15801561298257600080fd5b505af1158015612996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ba91906155be565b600b546040516395dd919360e01b81523060048201529192506000916001600160a01b03909116906395dd91939060240160206040518083038186803b158015612a0357600080fd5b505afa158015612a17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a3b91906155be565b90506000612a498284615aca565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98416906370a082319060240160206040518083038186803b158015612aae57600080fd5b505afa158015612ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae691906155be565b90506000612af48284615a73565b9050600086821115612b4e57612b0a8783615aca565b9a508a8311612b2457612b1d838c615aca565b9050612b49565b612b2e888c615a73565b8310612b3c57879850612b49565b612b468b84615aca565b98505b612b5b565b612b588288615aca565b99505b6000612b678a8a615aca565b90506000612b758383615a73565b90508015612bab576000612b888261351d565b905083811115612ba957612b9c8482615aca565b612ba6908d615a73565b9b505b505b50505050505050505050909192565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0316906370a082319060240160206040518083038186803b158015612c1c57600080fd5b505afa158015612c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5491906155be565b9050600080612c64836001613bb9565b91509150612c7183613db2565b600854610100900460ff168015612c885750600082115b15612cf75760008282604051602001612cad9291909182521515602082015260400190565b6040516020818303038152906040529050612ce97f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9848483613e7d565b612cf39084615aca565b9250505b60005b600083118015612d0b575060068111155b15612d3857612d1a8383614188565b612d249084615aca565b925080612d3081615b0d565b915050612cfa565b50505050565b60008083806020019051810190612d5591906155d6565b6040516370a0823160e01b815230600482015291935091506000906001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98416906370a082319060240160206040518083038186803b158015612dbc57600080fd5b505afa158015612dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df491906155be565b905082811015612e355760405162461bcd60e51b815260206004820152600c60248201526b11931054d217d1905253115160a21b6044820152606401610678565b8115612e5257612e448361427d565b612e4d84614348565b6112db565b612e5b81613db2565b6112db84614413565b604080516001808252818301909252600091602080830190803683375050600b5482519293506001600160a01b031691839150600090612eb457634e487b7160e01b600052603260045260246000fd5b6001600160a01b039092166020928302919091019091015260405162e1ed9760e51b8152733d9819210a31b4961b30ef54be2aed79b9c9cd3b90631c3db2e090612f04903090859060040161574c565b600060405180830381600087803b158015612f1e57600080fd5b505af11580156112db573d6000803e3d6000fd5b612f866001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984167f000000000000000000000000ff43c327410f960261057ba1da787ed78b42c257836144de565b600b54612fc0906001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98481169116836144de565b60005b600360009054906101000a90046001600160a01b03166001600160a01b031663c2fba6676040518163ffffffff1660e01b815260040160206040518083038186803b15801561301157600080fd5b505afa158015613025573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304991906155be565b8110156130fc57600354604051636e74a6f760e01b8152600481018390526130ea916001600160a01b031690636e74a6f79060240160206040518083038186803b15801561309657600080fd5b505afa1580156130aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ce9190615188565b73c00e94cb662c3520282e6f5717214004a7f2688890846144de565b806130f481615b0d565b915050612fc3565b506107437f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98482614602565b600b5460408051637e062a3560e11b815290516001600160a01b039283169284169163fc0c546a916004808301926020929190829003018186803b15801561316e57600080fd5b505afa158015613182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a69190615188565b6001600160a01b0316146131f25760405162461bcd60e51b81526020600482015260136024820152723bb937b73396b932b1b2b4b83a16ba37b5b2b760691b6044820152606401610678565b6000600955610743612bba565b6040516001600160a01b03831660248201526044810182905261126290849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526146c3565b600080821561333257600354604051631d1f307960e31b815273c00e94cb662c3520282e6f5717214004a7f2688860048201526001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98481166024830152604482018690529091169063e8f983c89060640160006040518083038186803b1580156132f157600080fd5b505afa158015613305573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261332d919081019061536d565b509150505b60008061333d611063565b6040516370a0823160e01b81523060048201529193509150819083906001600160a01b037f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98416906370a082319060240160206040518083038186803b1580156133a557600080fd5b505afa1580156133b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133dd91906155be565b6133e79086615a73565b6133f19190615a73565b6133fb9190615aca565b95945050505050565b804710156134545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610678565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146134a1576040519150601f19603f3d011682016040523d82523d6000602084013e6134a6565b606091505b50509050806112625760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610678565b600080600061352d846000613bb9565b9150915080156136dc57600854610100900460ff16156135b157600082826040516020016135679291909182521515602082015260400190565b60405160208183030381529060405290506135a37f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9848483613e7d565b6135ad9084615aca565b9250505b6000821180156135c3575060085460ff165b1561363257600082826040516020016135e89291909182521515602082015260400190565b60405160208183030381529060405290506136247f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9848483614795565b61362e9084615aca565b9250505b60005b6000831180156136465750600a8111155b1561367457613656836001614188565b6136609084615aca565b92508061366c81615b0d565b915050613635565b82156136da57600080613685611063565b9150915060006136936112e2565b9150506000816000146136ba57816136ad61271085615aab565b6136b79190615a8b565b90505b60006136c68286615aca565b9050808a11156136d4578099505b50505050505b505b6040516370a0823160e01b81523060048201526000907f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0316906370a082319060240160206040518083038186803b15801561373e57600080fd5b505afa158015613752573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377691906155be565b600b54604051633af9e66960e01b81523060048201529192506001600160a01b031690633af9e66990602401602060405180830381600087803b1580156137bc57600080fd5b505af11580156137d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f491906155be565b8511156138cb575060006138277f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984613b05565b6040516370a0823160e01b81523060048201527f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0316906370a082319060240160206040518083038186803b15801561388657600080fd5b505afa15801561389a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138be91906155be565b6138c89086615aca565b94505b6138d485614348565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0316906370a082319060240160206040518083038186803b15801561393657600080fd5b505afa15801561394a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396e91906155be565b905061397a8282615aca565b9695505050505050565b6000808390506000816001600160a01b031663295c39a56040518163ffffffff1660e01b815260040160206040518083038186803b1580156139c557600080fd5b505afa1580156139d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139fd91906155be565b90506000805b82811015613abc5760405163062bd3e960e01b8152600481018290526001600160a01b0385169063062bd3e99060240160206040518083038186803b158015613a4b57600080fd5b505afa158015613a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a839190615188565b9150856001600160a01b0316826001600160a01b03161415613aaa579350610c3492505050565b80613ab481615b0d565b915050613a03565b5060405162461bcd60e51b815260206004820152601b60248201527f6e6f2d6d61726b657449642d666f756e642d666f722d746f6b656e00000000006044820152606401610678565b613b0d612e64565b6040516370a0823160e01b815230600482015260009073c00e94cb662c3520282e6f5717214004a7f26888906370a082319060240160206040518083038186803b158015613b5a57600080fd5b505afa158015613b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9291906155be565b905080156109bc576109bc73c00e94cb662c3520282e6f5717214004a7f268888383614a09565b600b54604051633af9e66960e01b8152306004820152600091829182916001600160a01b031690633af9e66990602401602060405180830381600087803b158015613c0357600080fd5b505af1158015613c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3b91906155be565b600b546040516395dd919360e01b81523060048201529192506000916001600160a01b03909116906395dd91939060240160206040518083038186803b158015613c8457600080fd5b505afa158015613c98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbc91906155be565b905060095460001415613cd657925060019150613dab9050565b6000613ce28284615aca565b9050600086613d0857878211613cf9576000613d03565b613d038883615aca565b613d12565b613d128883615a73565b9050600080613d1f6112e2565b90925090506000613d3282612710615aca565b613d3c8386615aab565b613d469190615a8b565b90506000613d5684612710615aca565b613d608587615aab565b613d6a9190615a8b565b905081871115613d895760019850613d828188615aca565b9950613da2565b80871015613da25760009850613d9f8782615aca565b99505b50505050505050505b9250929050565b600b5460405163140e25ad60e31b8152600481018390526001600160a01b039091169063a0712d6890602401602060405180830381600087803b158015613df857600080fd5b505af1158015613e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e3091906155be565b156107435760405162461bcd60e51b815260206004820152601960248201527f737570706c792d746f2d636f6d706f756e642d6661696c6564000000000000006044820152606401610678565b600854600090610100900460ff16613ed75760405162461bcd60e51b815260206004820152601d60248201527f647964782d666c6173682d6c6f616e2d69732d6e6f742d6163746976650000006044820152606401610678565b506040516370a0823160e01b8152731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e600482015282906000906001600160a01b038616906370a082319060240160206040518083038186803b158015613f3057600080fd5b505afa158015613f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f6891906155be565b905080821115613f76578091505b6000613f83836002615a73565b905060008482604051602001613f9a92919061591e565b60408051808303601f19018152600380845260808401909252925060009190816020015b613fc66150b3565b815260200190600190039081613fbe579050509050613fe760075486614ada565b8160008151811061400857634e487b7160e01b600052603260045260246000fd5b602002602001018190525061401c82614b64565b8160018151811061403d57634e487b7160e01b600052603260045260246000fd5b602002602001018190525061405460075484614bd2565b8160028151811061407557634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081614097575050604080518082018252600080825260209182015281518083019092523082526001908201529091508160008151811061410657634e487b7160e01b600052603260045260246000fd5b602090810291909101015260405163a67a6a4560e01b8152731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e9063a67a6a459061414a90849086906004016157ee565b600060405180830381600087803b15801561416457600080fd5b505af1158015614178573d6000803e3d6000fd5b5050505050505050509392505050565b6000806000614195611063565b915091508060001480156141a65750835b156141b657600092505050610c34565b600b54604051638e8f294b60e01b81526001600160a01b039091166004820152600090733d9819210a31b4961b30ef54be2aed79b9c9cd3b90638e8f294b9060240160606040518083038186803b15801561421057600080fd5b505afa158015614224573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424891906154e7565b5091505084156142655761425e86848484614c0d565b9350614274565b61427186848484614c73565b93505b50505092915050565b600b5460405163073a938160e11b8152600481018390526001600160a01b0390911690630e75270290602401602060405180830381600087803b1580156142c357600080fd5b505af11580156142d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142fb91906155be565b156107435760405162461bcd60e51b815260206004820152601860248201527f72657061792d746f2d636f6d706f756e642d6661696c656400000000000000006044820152606401610678565b600b5460405163852a12e360e01b8152600481018390526001600160a01b039091169063852a12e390602401602060405180830381600087803b15801561438e57600080fd5b505af11580156143a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c691906155be565b156107435760405162461bcd60e51b815260206004820152601d60248201527f77697468647261772d66726f6d2d636f6d706f756e642d6661696c65640000006044820152606401610678565b600b5460405163317afabb60e21b8152600481018390526001600160a01b039091169063c5ebeaec90602401602060405180830381600087803b15801561445957600080fd5b505af115801561446d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061449191906155be565b156107435760405162461bcd60e51b815260206004820152601b60248201527f626f72726f772d66726f6d2d636f6d706f756e642d6661696c656400000000006044820152606401610678565b8015806145675750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561452d57600080fd5b505afa158015614541573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061456591906155be565b155b6145d25760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610678565b6040516001600160a01b03831660248201526044810182905261126290849063095ea7b360e01b9060640161322b565b61462a6001600160a01b038316731e0447b19bb6ecfdae1e4ae1694b0c3659614e4e836144de565b6109bc73b53c1a33016b2dc2ff3653530bff1848a515c8c56001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561467a57600080fd5b505afa15801561468e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146b29190615188565b6001600160a01b03841690836144de565b6000614718826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614d559092919063ffffffff16565b805190915015611262578080602001905181019061473691906154cb565b6112625760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610678565b60085460009060ff166147ea5760405162461bcd60e51b815260206004820152601d60248201527f616176652d666c6173682d6c6f616e2d69732d6e6f742d6163746976650000006044820152606401610678565b600073b53c1a33016b2dc2ff3653530bff1848a515c8c56001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561483957600080fd5b505afa15801561484d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148719190615188565b604080516001808252818301909252919250600091906020808301908036833701905050905085816000815181106148b957634e487b7160e01b600052603260045260246000fd5b6001600160a01b039290921660209283029190910190910152604080516001808252818301909252600091816020016020820280368337019050509050858160008151811061491857634e487b7160e01b600052603260045260246000fd5b602090810291909101015260408051600180825281830190925260009181602001602082028036833701905050905060008160008151811061496a57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526008805462ff000019166201000017905560405163ab9c4b5d60e01b81526001600160a01b0385169063ab9c4b5d906149bf90309087908790879084908e90600090600401615770565b600060405180830381600087803b1580156149d957600080fd5b505af11580156149ed573d6000803e3d6000fd5b50506008805462ff000019169055509698975050505050505050565b60006006546127101415614a1e576001614acc565b6040516358fac00360e01b81526001600160a01b0380861660048301526024820184905284166044820152610e106064820152614acc90730f1f5a87f99f0918e6c81f16e59f3518698221ff906358fac0039060840160206040518083038186803b158015614a8c57600080fd5b505afa158015614aa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ac491906155be565b600654614d6e565b9050612d3884848484614d91565b614ae26150b3565b604080516101008101825260018152600060208083018290528351608081018552828152929384019291908201905b81526020016000815260200185815250815260200184815260200160008152602001306001600160a01b031681526020016000815260200160405180602001604052806000815250815250905092915050565b614b6c6150b3565b6040805161010081018252600881526000602080830182905283516080810185528281529293840192919082019081526020016000815260006020918201819052918352820181905260408201819052306060830152608082015260a001929092525090565b614bda6150b3565b60408051610100810182526000808252602080830182905283516080810185526001815292938401929190820190614b11565b6000808215614c365782614c2985670de0b6b3a7640000615aab565b614c339190615a8b565b90505b614c408186615aca565b9150838210614c4d578391505b858210614c58578591505b614c6182614348565b614c6a8261427d565b50949350505050565b600080670de0b6b3a7640000614c898487615aab565b614c939190615a8b565b9050614c9f8482615aca565b9150858210614cac578591505b614cb582614413565b6040516370a0823160e01b8152306004820152614c6a907f0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0316906370a082319060240160206040518083038186803b158015614d1857600080fd5b505afa158015614d2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d5091906155be565b613db2565b6060614d648484600085614f52565b90505b9392505050565b6000612710614d7d8382615aca565b614d879085615aab565b614d679190615a8b565b600354604051631d1f307960e31b81526001600160a01b038681166004830152858116602483015260448201859052600092839283929091169063e8f983c89060640160006040518083038186803b158015614dec57600080fd5b505afa158015614e00573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052614e28919081019061536d565b9250925092508360001415614e3c57600193505b8115614f4957600354604051636e74a6f760e01b8152600481018390526001600160a01b0390911690636e74a6f79060240160206040518083038186803b158015614e8657600080fd5b505afa158015614e9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ebe9190615188565b6001600160a01b03166338ed173986868630426040518663ffffffff1660e01b8152600401614ef19594939291906159ba565b600060405180830381600087803b158015614f0b57600080fd5b505af1158015614f1f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052614f47919081019061541c565b505b50505050505050565b606082471015614fb35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610678565b843b6150015760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610678565b600080866001600160a01b0316858760405161501d9190615730565b60006040518083038185875af1925050503d806000811461505a576040519150601f19603f3d011682016040523d82523d6000602084013e61505f565b606091505b509150915061506f82828661507a565b979650505050505050565b60608315615089575081614d67565b8251156150995782518084602001fd5b8160405162461bcd60e51b81526004016106789190615940565b6040805161010081018252600080825260208201529081016150f7604080516080810190915260008082526020820190815260200160008152602001600081525090565b8152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b60008083601f84011261513a578182fd5b50813567ffffffffffffffff811115615151578182fd5b6020830191508360208260051b8501011115613dab57600080fd5b60006020828403121561517d578081fd5b8135614d6781615b7a565b600060208284031215615199578081fd5b8151614d6781615b7a565b600080600083850360808112156151b9578283fd5b84356151c481615b7a565b935060206040601f19830112156151d9578384fd5b6151e360406159f6565b9150808601356151f281615b7a565b825260408601358183015290925060608501359067ffffffffffffffff82111561521a578283fd5b818601915086601f83011261522d578283fd5b813561524061523b82615a4b565b6159f6565b8181528883838601011115615253578485fd5b818385018483013784838383010152809450505050509250925092565b600080600080600080600080600060a08a8c03121561528d578485fd5b893567ffffffffffffffff808211156152a4578687fd5b6152b08d838e01615129565b909b50995060208c01359150808211156152c8578687fd5b6152d48d838e01615129565b909950975060408c01359150808211156152ec578687fd5b6152f88d838e01615129565b909750955060608c0135915061530d82615b7a565b90935060808b01359080821115615322578384fd5b818c0191508c601f830112615335578384fd5b813581811115615343578485fd5b8d6020828501011115615354578485fd5b6020830194508093505050509295985092959850929598565b600080600060608486031215615381578283fd5b835167ffffffffffffffff811115615397578384fd5b8401601f810186136153a7578384fd5b805160206153b761523b83615a27565b8083825282820191508285018a848660051b88010111156153d6578889fd5b8895505b848610156154015780516153ed81615b7a565b8352600195909501949183019183016153da565b50918801516040909801519199979850909695505050505050565b6000602080838503121561542e578182fd5b825167ffffffffffffffff811115615444578283fd5b8301601f81018513615454578283fd5b805161546261523b82615a27565b80828252848201915084840188868560051b8701011115615481578687fd5b8694505b838510156154a3578051835260019490940193918501918501615485565b50979650505050505050565b6000602082840312156154c0578081fd5b8135614d6781615b8f565b6000602082840312156154dc578081fd5b8151614d6781615b8f565b6000806000606084860312156154fb578081fd5b835161550681615b8f565b60208501516040860151919450925061551e81615b8f565b809150509250925092565b6000806040838503121561553b578182fd5b825167ffffffffffffffff811115615551578283fd5b8301601f81018513615561578283fd5b805161556f61523b82615a4b565b818152866020838501011115615583578485fd5b615594826020830160208601615ae1565b60209590950151949694955050505050565b6000602082840312156155b7578081fd5b5035919050565b6000602082840312156155cf578081fd5b5051919050565b600080604083850312156155e8578182fd5b8251915060208301516155fa81615b8f565b809150509250929050565b60008060408385031215615617578182fd5b50508035926020909101359150565b6000806000806080858703121561563b578182fd5b505082516020840151604085015160609095015191969095509092509050565b6000815180845260208085019450808401835b838110156156935781516001600160a01b03168752958201959082019060010161566e565b509495945050505050565b6000815180845260208085019450808401835b83811015615693578151875295820195908201906001016156b1565b600081518084526156e5816020860160208601615ae1565b601f01601f19169290920160200192915050565b805115158252602081015161570d81615b6a565b6020830152604081015161572081615b6a565b6040830152606090810151910152565b60008251615742818460208701615ae1565b9190910192915050565b6001600160a01b0383168152604060208201819052600090614d649083018461565b565b600060018060a01b03808a16835260e0602084015261579260e084018a61565b565b83810360408501526157a4818a61569e565b905083810360608501526157b8818961569e565b9050818716608085015283810360a08501526157d481876156cd565b9250505061ffff831660c083015298975050505050505050565b6040808252835182820181905260009190606090818501906020808901865b8381101561583b57815180516001600160a01b0316865283015183860152938601939082019060010161580d565b50508683038188015287518084528184019250600581901b84018201898301885b8381101561590d57601f19878403018652815161016081516009811061588457615884615b3e565b855281870151878601528a82015161589e8c8701826156f9565b508982015160c081818801526080840151915060e0828189015260a085015192506158d56101008901846001600160a01b03169052565b9084015161012088015290920151610140860182905291506158f9818601836156cd565b97870197945050509084019060010161585c565b50909b9a5050505050505050505050565b60006040825261593160408301856156cd565b90508260208301529392505050565b600060208252614d6760208301846156cd565b60208082526016908201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b604082015260600190565b6020808252601a908201527f63616c6c65722d69732d6e6f742d7468652d676f7665726e6f72000000000000604082015260600190565b600086825285602083015260a060408301526159d960a083018661565b565b6001600160a01b0394909416606083015250608001529392505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715615a1f57615a1f615b54565b604052919050565b600067ffffffffffffffff821115615a4157615a41615b54565b5060051b60200190565b600067ffffffffffffffff821115615a6557615a65615b54565b50601f01601f191660200190565b60008219821115615a8657615a86615b28565b500190565b600082615aa657634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615ac557615ac5615b28565b500290565b600082821015615adc57615adc615b28565b500390565b60005b83811015615afc578181015183820152602001615ae4565b83811115612d385750506000910152565b6000600019821415615b2157615b21615b28565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6002811061074357610743615b3e565b6001600160a01b038116811461074357600080fd5b801515811461074357600080fdfea2646970667358221220a62e284941a615045dec466ea4ca927f82f95e987ed2d8f21a4f991d746beaa064736f6c63430008030033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ff43c327410f960261057ba1da787ed78b42c257000000000000000000000000e382d9f2394a359b01006faa8a1864b8a60d2710
-----Decoded View---------------
Arg [0] : _pool (address): 0xfF43C327410F960261057ba1DA787eD78B42c257
Arg [1] : _swapManager (address): 0xe382d9f2394A359B01006faa8A1864b8a60d2710
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000ff43c327410f960261057ba1da787ed78b42c257
Arg [1] : 000000000000000000000000e382d9f2394a359b01006faa8a1864b8a60d2710
Loading...
Loading
Loading...
Loading
Net Worth in USD
$28.13
Net Worth in ETH
0.013988
Token Allocations
CUNI
100.00%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $0.080383 | 350 | $28.13 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.