Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- VaultUtils
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- EVM Version
- istanbul
- Verified at
- 2023-09-15T17:56:58.981289Z
contracts/protocol/libraries/utils/VaultUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;
import "../../../dependencies/openzeppelin/contracts/IERC20.sol";
import "../../../dependencies/openzeppelin/contracts/SafeMath.sol";
import "../../../interfaces/IAddressesProvider.sol";
import "../../../interfaces/IVault.sol";
import "../../../interfaces/IVaultConfigurator.sol";
import "../../../interfaces/IPhamePriceOracle.sol";
import "../helpers/Errors.sol";
library VaultUtils {
using SafeMath for uint256;
struct Position {
uint256 size;
uint256 collateral;
uint256 averagePrice;
uint256 entryFundingRate;
uint256 reserveAmount;
int256 realisedPnl;
uint256 lastIncreasedTime;
}
uint256 public constant BASIS_POINTS_DIVISOR = 10000;
uint256 public constant FUNDING_RATE_PRECISION = 1000000;
function validateLiquidation(
IAddressesProvider addressesProvider,
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
bool _raise
) public view returns (uint256, uint256) {
IVault vault = IVault(addressesProvider.getVault());
Position memory position = _getPosition(
vault,
_account,
_collateralToken,
_indexToken,
_isLong
);
(bool hasProfit, uint256 delta) = vault.getDelta(
_indexToken,
position.size,
position.averagePrice,
_isLong,
position.lastIncreasedTime
);
uint256 marginFees = getFundingFee(
vault,
_account,
_collateralToken,
_indexToken,
_isLong,
position.size,
position.entryFundingRate
).add(
getPositionFee(
addressesProvider,
_account,
_collateralToken,
_indexToken,
_isLong,
position.size
)
);
if (!hasProfit && position.collateral < delta) {
if (_raise) {
revert("VaultUtils: losses exceed collateral");
}
return (1, marginFees);
}
uint256 remainingCollateral = position.collateral;
if (!hasProfit) {
remainingCollateral = position.collateral.sub(delta);
}
if (remainingCollateral < marginFees) {
if (_raise) {
revert("VaultUtils: fees exceed collateral");
}
// cap the fees to the remainingCollateral
return (1, remainingCollateral);
}
DataTypes.VaultConfig memory vaultConfig = IVault(
addressesProvider.getVault()
).getVaultConfig();
if (
remainingCollateral < marginFees.add(vaultConfig.liquidationFeeUsd)
) {
if (_raise) {
revert("VaultUtils: liquidation fees exceed collateral");
}
return (1, marginFees);
}
if (
remainingCollateral.mul(vaultConfig.maxLeverage) <
position.size.mul(BASIS_POINTS_DIVISOR)
) {
if (_raise) {
revert("VaultUtils: maxLeverage exceeded");
}
return (2, marginFees);
}
return (0, marginFees);
}
function updateCumulativeFundingRate(
address /* _collateralToken */,
address /* _indexToken */
) public pure returns (bool) {
return true;
}
function getEntryFundingRate(
IVault vault,
address _collateralToken,
address /* _indexToken */,
bool /* _isLong */
) public view returns (uint256) {
return vault.cumulativeFundingRates(_collateralToken);
}
function getNextFundingRate(
IAddressesProvider addressesProvider,
address _token
) public view returns (uint256) {
IVault vault = IVault(addressesProvider.getVault());
DataTypes.VaultConfig memory vaultConfig = vault.getVaultConfig();
uint256 fundingInterval = vaultConfig.fundingInterval;
if (
vault.lastFundingTimes(_token).add(fundingInterval) >
block.timestamp
) {
return 0;
}
uint256 intervals = block
.timestamp
.sub(vault.lastFundingTimes(_token))
.div(fundingInterval);
uint256 poolAmount = vault.poolAmounts(_token);
if (poolAmount == 0) {
return 0;
}
uint256 _fundingRateFactor = vault.getTokenConfig(_token).isStable
? vaultConfig.stableFundingRateFactor
: vaultConfig.fundingRateFactor;
return
_fundingRateFactor
.mul(vault.reservedAmounts(_token))
.mul(intervals)
.div(poolAmount);
}
function getPositionFee(
IAddressesProvider addressesProvider,
address /* _account */,
address /* _collateralToken */,
address /* _indexToken */,
bool /* _isLong */,
uint256 _sizeDelta
) public view returns (uint256) {
if (_sizeDelta == 0) {
return 0;
}
uint256 afterFeeUsd = _sizeDelta
.mul(
BASIS_POINTS_DIVISOR.sub(
IVault(addressesProvider.getVault())
.getVaultConfig()
.marginFeeBps
)
)
.div(BASIS_POINTS_DIVISOR);
return _sizeDelta.sub(afterFeeUsd);
}
function getFundingFee(
IVault vault,
address /* _account */,
address _collateralToken,
address /* _indexToken */,
bool /* _isLong */,
uint256 _size,
uint256 _entryFundingRate
) public view returns (uint256) {
if (_size == 0) {
return 0;
}
uint256 fundingRate = vault
.cumulativeFundingRates(_collateralToken)
.sub(_entryFundingRate);
if (fundingRate == 0) {
return 0;
}
return _size.mul(fundingRate).div(FUNDING_RATE_PRECISION);
}
function getBuyUsdphFeeBps(
IAddressesProvider addressesProvider,
address _token,
uint256 _usdphAmount
) public view returns (uint256) {
DataTypes.VaultConfig memory vaultConfig = IVault(
addressesProvider.getVault()
).getVaultConfig();
return
getFeeBps(
addressesProvider,
_token,
_usdphAmount,
vaultConfig.mintBurnFeeBps,
vaultConfig.taxBps,
true
);
}
function getSellUsdphFeeBps(
IAddressesProvider addressesProvider,
address _token,
uint256 _usdphAmount
) public view returns (uint256) {
DataTypes.VaultConfig memory vaultConfig = IVault(
addressesProvider.getVault()
).getVaultConfig();
return
getFeeBps(
addressesProvider,
_token,
_usdphAmount,
vaultConfig.mintBurnFeeBps,
vaultConfig.taxBps,
false
);
}
function getSwapFeeBps(
IAddressesProvider addressesProvider,
address _tokenIn,
address _tokenOut,
uint256 _usdphAmount
) public view returns (uint256) {
IVault vault = IVault(addressesProvider.getVault());
(uint256 baseBps, uint256 taxBps) = IVaultConfigurator(
addressesProvider.getVaultConfigurator()
).getSwapFeeAndTaxBps(
vault.getTokenConfig(_tokenIn).isStable &&
vault.getTokenConfig(_tokenOut).isStable
);
uint256 feesBps0 = getFeeBps(
addressesProvider,
_tokenIn,
_usdphAmount,
baseBps,
taxBps,
true
);
uint256 feesBps1 = getFeeBps(
addressesProvider,
_tokenOut,
_usdphAmount,
baseBps,
taxBps,
false
);
// use the higher of the two fee basis points
return feesBps0 > feesBps1 ? feesBps0 : feesBps1;
}
// cases to consider
// 1. initialAmount is far from targetAmount, action increases balance slightly => high rebate
// 2. initialAmount is far from targetAmount, action increases balance largely => high rebate
// 3. initialAmount is close to targetAmount, action increases balance slightly => low rebate
// 4. initialAmount is far from targetAmount, action reduces balance slightly => high tax
// 5. initialAmount is far from targetAmount, action reduces balance largely => high tax
// 6. initialAmount is close to targetAmount, action reduces balance largely => low tax
// 7. initialAmount is above targetAmount, nextAmount is below targetAmount and vice versa
// 8. a large swap should have similar fees as the same trade split into multiple smaller swaps
function getFeeBps(
IAddressesProvider addressesProvider,
address _token,
uint256 _usdphDelta,
uint256 _feeBps,
uint256 _taxBps,
bool _increment
) public view returns (uint256) {
if (
!IVault(addressesProvider.getVault())
.getVaultConfig()
.hasDynamicFees
) {
return _feeBps;
}
uint256 initialAmount = IVault(addressesProvider.getVault())
.usdphAmounts(_token);
uint256 nextAmount = initialAmount.add(_usdphDelta);
if (!_increment) {
nextAmount = _usdphDelta > initialAmount
? 0
: initialAmount.sub(_usdphDelta);
}
uint256 targetAmount = _getTargetUsdphAmount(addressesProvider, _token);
if (targetAmount == 0) {
return _feeBps;
}
uint256 initialDiff = initialAmount > targetAmount
? initialAmount.sub(targetAmount)
: targetAmount.sub(initialAmount);
uint256 nextDiff = nextAmount > targetAmount
? nextAmount.sub(targetAmount)
: targetAmount.sub(nextAmount);
// action improves relative asset balance
if (nextDiff < initialDiff) {
uint256 rebateBps = _taxBps.mul(initialDiff).div(targetAmount);
return rebateBps > _feeBps ? 0 : _feeBps.sub(rebateBps);
}
uint256 averageDiff = initialDiff.add(nextDiff).div(2);
if (averageDiff > targetAmount) {
averageDiff = targetAmount;
}
uint256 taxBps = _taxBps.mul(averageDiff).div(targetAmount);
return _feeBps.add(taxBps);
}
function getDelta(
IAddressesProvider addressesProvider,
address _indexToken,
uint256 _size,
uint256 _averagePrice,
bool _isLong,
uint256 _lastIncreasedTime
) public view returns (bool, uint256) {
require(_averagePrice > 0, Errors.VU_INVALID_AVERAGE_PRICE);
uint256 price = IPhamePriceOracle(addressesProvider.getPriceOracle())
.getPrice(_indexToken, !_isLong);
uint256 priceDelta = _averagePrice > price
? _averagePrice.sub(price)
: price.sub(_averagePrice);
uint256 delta = _size.mul(priceDelta).div(_averagePrice);
bool hasProfit;
if (_isLong) {
hasProfit = price > _averagePrice;
} else {
hasProfit = _averagePrice > price;
}
// if the minProfitTime has passed then there will be no min profit threshold
// the min profit threshold helps to prevent front-running issues
IVault vault = IVault(addressesProvider.getVault());
uint256 minBps = block.timestamp >
_lastIncreasedTime.add(vault.getVaultConfig().minProfitTime)
? 0
: vault.getTokenConfig(_indexToken).minProfitBps;
if (hasProfit && delta.mul(BASIS_POINTS_DIVISOR) <= _size.mul(minBps)) {
delta = 0;
}
return (hasProfit, delta);
}
function _getPosition(
IVault vault,
address _account,
address _collateralToken,
address _indexToken,
bool _isLong
) private view returns (Position memory) {
Position memory position;
{
(
uint256 size,
uint256 collateral,
uint256 averagePrice,
uint256 entryFundingRate /* reserveAmount */ /* realisedPnl */ /* hasProfit */,
,
,
,
uint256 lastIncreasedTime
) = vault.getPosition(
_account,
_collateralToken,
_indexToken,
_isLong
);
position.size = size;
position.collateral = collateral;
position.averagePrice = averagePrice;
position.entryFundingRate = entryFundingRate;
position.lastIncreasedTime = lastIncreasedTime;
}
return position;
}
function _getTargetUsdphAmount(
IAddressesProvider addressesProvider,
address _token
) private view returns (uint256) {
uint256 supply = IERC20(addressesProvider.getUsdph()).totalSupply();
if (supply == 0) {
return 0;
}
IVault vault = IVault(addressesProvider.getVault());
uint256 weight = vault.getTokenConfig(_token).weight;
return weight.mul(supply).div(vault.totalTokenWeights());
}
}
contracts/dependencies/openzeppelin/contracts/IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <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
);
}
contracts/dependencies/openzeppelin/contracts/SafeMath.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
contracts/interfaces/IAddressesProvider.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.6;
interface IAddressesProvider {
function getUsdph() external view returns (address);
function getPhlp() external view returns (address);
function getPhlpManager() external view returns (address);
function getVault() external view returns (address);
function getVaultConfigurator() external view returns (address);
function getRouter() external view returns (address);
function getOrderBook() external view returns (address);
function getPositionManager() external view returns (address);
function getPositionRouter() external view returns (address);
function getPriceOracle() external view returns (address);
function getShortsTracker() external view returns (address);
function getTreasury() external view returns (address payable);
}
contracts/interfaces/IPhamePriceOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
interface IPhamePriceOracle {
function backupPriceOracle() external view returns (address);
function adjustmentBps(address _token) external view returns (uint256);
function isAdjustmentAdditive(address _token) external view returns (bool);
function setAdjustment(
address _token,
bool _isAdditive,
uint256 _adjustmentBps
) external;
function setSpreadBps(address _token, uint256 _spreadBps) external;
function setSpreadThresholdBps(uint256 _spreadThresholdBps) external;
function setPriceSampleSpace(uint256 _priceSampleSpace) external;
function setMaxStrictPriceDeviation(
uint256 _maxStrictPriceDeviation
) external;
function getPrice(
address _token,
bool _maximise
) external view returns (uint256);
function setTokenConfig(
address _token,
address _priceFeed,
uint256 _priceDecimals,
bool _isStrictStable
) external;
}
contracts/interfaces/IVault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;
import "../protocol/libraries/types/DataTypes.sol";
import "./IAddressesProvider.sol";
interface IVault {
struct Position {
uint256 size;
uint256 collateral;
uint256 averagePrice;
uint256 entryFundingRate;
uint256 reserveAmount;
int256 realisedPnl;
uint256 lastIncreasedTime;
}
event BuyUSDPH(
address account,
address token,
uint256 tokenAmount,
uint256 usdphAmount,
uint256 feeBps
);
event SellUSDPH(
address account,
address token,
uint256 usdphAmount,
uint256 tokenAmount,
uint256 feeBps
);
event Swap(
address account,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOut,
uint256 amountOutAfterFees,
uint256 feeBps
);
event IncreasePosition(
bytes32 key,
address account,
address collateralToken,
address indexToken,
uint256 collateralDelta,
uint256 sizeDelta,
bool isLong,
uint256 price,
uint256 fee
);
event DecreasePosition(
bytes32 key,
address account,
address collateralToken,
address indexToken,
uint256 collateralDelta,
uint256 sizeDelta,
bool isLong,
uint256 price,
uint256 fee
);
event LiquidatePosition(
bytes32 key,
address account,
address collateralToken,
address indexToken,
bool isLong,
uint256 size,
uint256 collateral,
uint256 reserveAmount,
int256 realisedPnl,
uint256 markPrice
);
event UpdatePosition(
bytes32 key,
uint256 size,
uint256 collateral,
uint256 averagePrice,
uint256 entryFundingRate,
uint256 reserveAmount,
int256 realisedPnl,
uint256 markPrice
);
event ClosePosition(
bytes32 key,
uint256 size,
uint256 collateral,
uint256 averagePrice,
uint256 entryFundingRate,
uint256 reserveAmount,
int256 realisedPnl
);
event UpdateFundingRate(address token, uint256 fundingRate);
event UpdatePnl(bytes32 key, bool hasProfit, uint256 delta);
event CollectSwapFees(address token, uint256 feeUsd, uint256 feeTokens);
event CollectMarginFees(address token, uint256 feeUsd, uint256 feeTokens);
event PayLpFees(address token, uint256 feeTokens);
event DirectPoolDeposit(address token, uint256 amount);
event IncreasePoolAmount(address token, uint256 amount);
event DecreasePoolAmount(address token, uint256 amount);
event IncreaseUsdphAmount(address token, uint256 amount);
event DecreaseUsdphAmount(address token, uint256 amount);
event IncreaseReservedAmount(address token, uint256 amount);
event DecreaseReservedAmount(address token, uint256 amount);
event IncreaseGuaranteedUsd(address token, uint256 amount);
event DecreaseGuaranteedUsd(address token, uint256 amount);
function addressesProvider() external view returns (IAddressesProvider);
function getVaultConfig()
external
view
returns (DataTypes.VaultConfig memory);
function setVaultConfig(
DataTypes.VaultConfig calldata vaultConfig
) external;
function allWhitelistedTokensLength() external view returns (uint256);
function totalTokenWeights() external view returns (uint256);
function allWhitelistedTokens(uint256) external view returns (address);
function getTokenConfig(
address _token
) external view returns (DataTypes.TokenConfig memory);
function setTokenConfig(
address _token,
DataTypes.TokenConfig calldata tokenConfig
) external;
function clearTokenConfig(address _token) external;
function setUsdphAmount(address _token, uint256 _amount) external;
function tokenBalances(address _token) external view returns (uint256);
function lastFundingTimes(address _token) external view returns (uint256);
function withdrawFees(
address _token,
address _receiver
) external returns (uint256);
function directPoolDeposit(address _token) external;
function buyUSDPH(
address _token,
address _receiver
) external returns (uint256);
function buyUSDPHwithoutFee(address _token) external returns (uint256);
function sellUSDPH(
address _token,
address _receiver
) external returns (uint256);
function swap(
address _tokenIn,
address _tokenOut,
address _receiver
) external returns (uint256);
function increasePosition(
address _account,
address _collateralToken,
address _indexToken,
uint256 _sizeDelta,
bool _isLong
) external;
function decreasePosition(
address _account,
address _collateralToken,
address _indexToken,
uint256 _collateralDelta,
uint256 _sizeDelta,
bool _isLong,
address _receiver
) external returns (uint256);
function validateLiquidation(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
bool _raise
) external view returns (uint256, uint256);
function liquidatePosition(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong,
address _feeReceiver
) external;
function tokenToUsdMin(
address _token,
uint256 _tokenAmount
) external view returns (uint256);
function cumulativeFundingRates(
address _token
) external view returns (uint256);
function getNextFundingRate(address _token) external view returns (uint256);
function getFeeBps(
address _token,
uint256 _usdphDelta,
uint256 _feeBps,
uint256 _taxBps,
bool _increment
) external view returns (uint256);
function feeReserves(address _token) external view returns (uint256);
function globalShortSizes(address _token) external view returns (uint256);
function guaranteedUsd(address _token) external view returns (uint256);
function poolAmounts(address _token) external view returns (uint256);
function reservedAmounts(address _token) external view returns (uint256);
function usdphAmounts(address _token) external view returns (uint256);
function getRedemptionAmount(
address _token,
uint256 _usdphAmount
) external view returns (uint256);
function getDelta(
address _indexToken,
uint256 _size,
uint256 _averagePrice,
bool _isLong,
uint256 _lastIncreasedTime
) external view returns (bool, uint256);
function getPosition(
address _account,
address _collateralToken,
address _indexToken,
bool _isLong
)
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
bool,
uint256
);
}
contracts/interfaces/IVaultConfigurator.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;
interface IVaultConfigurator {
function setIsLeverageEnabled(bool _isLeverageEnabled) external;
function setStakingBps(uint256 _stakingBps) external;
function setUsdphAmount(address _token, uint256 _amount) external;
function getSwapFeeAndTaxBps(
bool isStableSwap
) external view returns (uint256, uint256);
}
contracts/protocol/libraries/helpers/Errors.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.6;
library Errors {
uint256 public constant V_TOKEN_NOT_WHITELISTED = 14; // Vault: token not whitelisted
uint256 public constant V_INVALID_TOKEN_AMOUNT = 15; // Vault: invalid tokenAmount
uint256 public constant V_INVALID_USDPH_AMOUNT = 18; // Vault: invalid usdphAmount
uint256 public constant V_INVALID_REDEMPTION_AMOUNT = 21; // Vault: invalid redemptionAmount
uint256 public constant V_INVALID_AMOUNT_OUT = 22; // Vault: invalid amountOut
uint256 public constant V_SWAPS_NOT_ENABLED = 23; // Vault: swaps not enabled
uint256 public constant V_SAME_TOKEN = 26; // Vault: same token in and out
uint256 public constant V_INVALID_AMOUNT_IN = 27; // Vault: invalid amountIn
uint256 public constant V_INSUFFICIENT_COLLATERAL_FOR_FEES = 29; // Vault: insufficient collateral for fees
uint256 public constant V_INVALID_POSITION_SIZE = 30; // Vault: invalid position.size
uint256 public constant V_EMPTY_POSITION = 31; // Vault: empty position
uint256 public constant V_POSITION_SIZE_EXCEEDED = 32; // Vault: position size exceeded
uint256 public constant V_POSITION_COLLATERAL_EXCEEDED = 33; // Vault: position collateral exceeded
uint256 public constant V_INVALID_LIQUIDATOR = 34; // Vault: invalid liquidator
uint256 public constant V_POSITION_CANNOT_BE_LIQUIDATED = 36; // Vault: position cannot be liquidated
uint256 public constant V_COLLATERAL_SHOULD_BE_WITHDRAWN = 39; // Vault: collateral should be withdrawn
uint256 public constant V_SIZE_MUST_BE_MORE_THAN_COLLATERAL = 40; // Vault: size must be more than collateral
uint256 public constant V_POOL_AMOUNT_EXCEEDS_BALANCE = 49; // Vault: pool amount exceeds balance
uint256 public constant V_RESERVE_EXCEEDS_POOL = 50; // Vault: reserve exceeds pool
uint256 public constant V_MAX_USDPH_EXCEEDED = 51; // Vault: max USDPH exceeded
uint256 public constant V_NOT_PHLP_MANAGER = 54; // Vault: caller is not PHLP Manager
uint256 public constant V_POOL_LESS_THAN_BUFFER = 100; // Vault: poolAmount < bufferAmount
uint256 public constant V_MAX_SHORTS_EXCEEDED = 101; // Vault: max shorts exceeded
uint256 public constant V_NOT_CONFIGURATOR = 102; // Vault: caller is not the vault configurator
uint256 public constant V_NOT_ROUTER = 103; // Vault: caller is not the router
string public constant VC_INVALID_STAKING_BPS = "1"; // VaultConfigurator: invalid stakingBps
string public constant VC_INVALID_MAX_LEVERAGE = "2"; // VaultConfigurator: invalid maxLeverage
string public constant VC_INVALID_TAX_BPS = "3"; // VaultConfigurator: invalid taxBps
string public constant VC_INVALID_STABLE_TAX_BPS = "4"; // VaultConfigurator: invalid stableTaxBps
string public constant VC_INVALID_MINT_BURN_FEE_BPS = "5"; // VaultConfigurator: invalid mintBurnFeeBps
string public constant VC_INVALID_SWAP_FEE_BPS = "6"; // VaultConfigurator: invalid swapFeeBps
string public constant VC_INVALID_STABLE_SWAP_FEE_BPS = "7"; // VaultConfigurator: invalid stableSwapFeeBps
string public constant VC_INVALID_MARGIN_FEE_BPS = "8"; // VaultConfigurator: invalid marginFeeBps
string public constant VC_INVALID_LIQUIDATION_FEE_USD = "9"; // VaultConfigurator: invalid _liquidationFeeUsd
string public constant VC_INVALID_FUNDING_INTERVAL = "10"; // VaultConfigurator: invalid fundingInterval
string public constant VC_INVALID_FUNDING_RATE_FACTOR = "11"; // VaultConfigurator: invalid fundingRateFactor
string public constant VC_INVALID_STABLE_FUNDING_RATE_FACTOR = "12"; // VaultConfigurator: invalid stableFundingRateFactor
string public constant VC_TOKEN_NOT_WHITELISTED = "13"; // VaultConfigurator: token not whitelisted
string public constant VU_LEVERAGE_NOT_ENABLED = "28"; // VaultUtil: leverage not enabled
string public constant VU_INVALID_AVERAGE_PRICE = "38"; // VaultUtil: invalid averagePrice
string public constant VU_INVALID_MSG_SENDER = "41"; // VaultUtil: invalid msg.sender
string public constant TCL_MISMATCHED_TOKENS = "42"; // TokenConfigsLogic: mismatched tokens
string public constant TCL_COLLATERAL_TOKEN_NOT_WHITELISTED = "43"; // TokenConfigsLogic: collateralToken not whitelisted
string public constant TCL_COLLATERAL_TOKEN_MUST_NOT_BE_STABLE = "44"; // TokenConfigsLogic: collateralToken must not be a stableToken
string public constant TCL_COLLATERAL_TOKEN_MUST_BE_STABLE = "46"; // TokenConfigsLogic: collateralToken must be a stableToken
string public constant TCL_INDEX_TOKEN_MUST_NOT_BE_STABLE = "47"; // TokenConfigsLogic: indexToken must not be a stableToken
string public constant TCL_INDEX_TOKEN_NOT_SHORTABLE = "48"; // TokenConfigsLogic: indexToken not shortable
string public constant TCL_TOKEN_NOT_WHITELISTED = "200"; // TokenConfigsLogic: token not whitelisted
string public constant TCL_INVALID_TOKEN_WEIGHT = "201"; // TokenConfigsLogic: invalid token weight
}
contracts/protocol/libraries/types/DataTypes.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.6;
library DataTypes {
struct VaultConfig {
bool isSwapEnabled;
bool isLeverageEnabled;
uint256 maxLeverage;
// fees
uint256 taxBps;
uint256 stableTaxBps;
uint256 mintBurnFeeBps;
uint256 swapFeeBps;
uint256 stableSwapFeeBps;
uint256 marginFeeBps;
uint256 liquidationFeeUsd;
uint256 minProfitTime;
bool hasDynamicFees;
// staking
uint256 stakingBps;
// funding rate
uint256 fundingInterval;
uint256 fundingRateFactor;
uint256 stableFundingRateFactor;
}
struct TokenConfig {
// should always be true if token exists
bool isWhitelisted;
// basic parameters
uint256 decimals;
uint256 weight; // customisation of index composition
uint256 minProfitBps;
uint256 maxUsdphAmount; // a max amount of USDPH debt for a token
bool isStable;
bool isShortable;
// risk parameters
// bufferAmount allows specification of an amount to exclude from swaps
// this can be used to ensure a certain amount of liquidity is available for leverage positions
uint256 bufferAmount;
uint256 maxGlobalShortSize;
}
struct TokenConfigs {
uint256 totalTokenWeights;
address[] allWhitelistedTokens;
mapping(address => TokenConfig) tokenConfigs;
}
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"istanbul"}
Contract ABI
[{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BASIS_POINTS_DIVISOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"FUNDING_RATE_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBuyUsdphFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDelta","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_averagePrice","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_lastIncreasedTime","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getEntryFundingRate","inputs":[{"type":"IVault","name":"vault","internalType":"contract IVault"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"bool","name":"","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphDelta","internalType":"uint256"},{"type":"uint256","name":"_feeBps","internalType":"uint256"},{"type":"uint256","name":"_taxBps","internalType":"uint256"},{"type":"bool","name":"_increment","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getFundingFee","inputs":[{"type":"IVault","name":"vault","internalType":"contract IVault"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_entryFundingRate","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNextFundingRate","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPositionFee","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSellUsdphFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSwapFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_tokenIn","internalType":"address"},{"type":"address","name":"_tokenOut","internalType":"address"},{"type":"uint256","name":"_usdphAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"updateCumulativeFundingRate","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"validateLiquidation","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"bool","name":"_raise","internalType":"bool"}]}]
Contract Creation Code
0x61247c610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100d85760003560e01c806387e35c2c11610096578063cfb90b2011610070578063cfb90b2014610196578063d4b9aa63146101b7578063dbeac656146101ca578063fbfded6d146101dd576100d8565b806387e35c2c1461015d578063ac56fc0e14610170578063c1a83e2a14610183576100d8565b80628d73e6146100dd578063126082cf1461010657806323a0ec041461010e578063429a429f146101215780634e9c9175146101345780636be6026b14610155575b600080fd5b6100f06100eb366004611c8d565b6101fd565b6040516100fd91906123c4565b60405180910390f35b6100f06105f2565b6100f061011c366004611e79565b6105f8565b6100f061012f366004611f53565b6108ff565b610147610142366004611c9f565b610987565b6040516100fd9291906123cd565b6100f0610d18565b6100f061016b366004611d98565b610d1f565b6100f061017e366004611de8565b610fd3565b6100f0610191366004611de8565b6110d1565b6101a96101a4366004611e28565b6111cf565b6040516100fd929190612258565b6100f06101c5366004611d20565b611517565b6100f06101d8366004611ed1565b61163c565b6101f06101eb366004611c28565b611704565b6040516100fd919061224d565b600080836001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561023957600080fd5b505afa15801561024d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102719190611c0c565b90506000816001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b1580156102af57600080fd5b505afa1580156102c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e7919061203f565b90506000816101a0015190504261037a82856001600160a01b031663d8f897c3896040518263ffffffff1660e01b815260040161032491906121c4565b60206040518083038186803b15801561033c57600080fd5b505afa158015610350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103749190612120565b9061170c565b111561038c57600093505050506105ec565b600061041e82610418866001600160a01b031663d8f897c38a6040518263ffffffff1660e01b81526004016103c191906121c4565b60206040518083038186803b1580156103d957600080fd5b505afa1580156103ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104119190612120565b429061176d565b906117ca565b90506000846001600160a01b03166352f55eed886040518263ffffffff1660e01b815260040161044e91906121c4565b60206040518083038186803b15801561046657600080fd5b505afa15801561047a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049e9190612120565b9050806104b3576000955050505050506105ec565b60405163cb67e3b160e01b81526000906001600160a01b0387169063cb67e3b1906104e2908b906004016121c4565b6101206040518083038186803b1580156104fb57600080fd5b505afa15801561050f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105339190611fae565b60a0015161054657846101c0015161054d565b846101e001515b90506105e382610418856105dd8a6001600160a01b031663c3c7b9e98e6040518263ffffffff1660e01b815260040161058691906121c4565b60206040518083038186803b15801561059e57600080fd5b505afa1580156105b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d69190612120565b8690611831565b90611831565b96505050505050505b92915050565b61271081565b6000866001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561063357600080fd5b505afa158015610647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066b9190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b1580156106a457600080fd5b505afa1580156106b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106dc919061203f565b61016001516106ec5750826108f5565b6000876001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561072757600080fd5b505afa15801561073b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075f9190611c0c565b6001600160a01b03166342e85182886040518263ffffffff1660e01b815260040161078a91906121c4565b60206040518083038186803b1580156107a257600080fd5b505afa1580156107b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107da9190612120565b905060006107e8828861170c565b90508361080b5781871161080557610800828861176d565b610808565b60005b90505b60006108178a8a61188a565b905080610829578693505050506108f5565b60008184116108415761083c828561176d565b61084b565b61084b848361176d565b9050600082841161086557610860838561176d565b61086f565b61086f848461176d565b9050818110156108b1576000610889846104188b86611831565b90508981116108a15761089c8a8261176d565b6108a4565b60005b96505050505050506108f5565b60006108c26002610418858561170c565b9050838111156108cf5750825b60006108df856104188c85611831565b90506108eb8b8261170c565b9750505050505050505b9695505050505050565b60405163c65bc7b160e01b81526000906001600160a01b0386169063c65bc7b19061092e9087906004016121c4565b60206040518083038186803b15801561094657600080fd5b505afa15801561095a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097e9190612120565b95945050505050565b6000806000886001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156109c557600080fd5b505afa1580156109d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fd9190611c0c565b90506000610a0e828a8a8a8a611af7565b805160408083015160c08401519151635c07eaab60e01b815293945060009384936001600160a01b03881693635c07eaab93610a51938f93928f9160040161221d565b604080518083038186803b158015610a6857600080fd5b505afa158015610a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa09190611c60565b915091506000610ad2610abb8e8e8e8e8e8a60000151611517565b610374878f8f8f8f8b600001518c6060015161163c565b905082158015610ae55750818460200151105b15610b21578715610b115760405162461bcd60e51b8152600401610b08906122bb565b60405180910390fd5b600196509450610d0d9350505050565b602084015183610b3d576020850151610b3a908461176d565b90505b81811015610b74578815610b635760405162461bcd60e51b8152600401610b0890612382565b600197509550610d0d945050505050565b60008e6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610baf57600080fd5b505afa158015610bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be79190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b158015610c2057600080fd5b505afa158015610c34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c58919061203f565b9050610c728161012001518461170c90919063ffffffff16565b821015610caa578915610c975760405162461bcd60e51b8152600401610b0890612334565b6001839850985050505050505050610d0d565b8551610cb890612710611831565b6040820151610cc8908490611831565b1015610cff578915610cec5760405162461bcd60e51b8152600401610b08906122ff565b6002839850985050505050505050610d0d565b506000975090955050505050505b965096945050505050565b620f424081565b600080856001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610d5b57600080fd5b505afa158015610d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d939190611c0c565b9050600080876001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610dd157600080fd5b505afa158015610de5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e099190611c0c565b6001600160a01b031663eab4d7a9846001600160a01b031663cb67e3b18a6040518263ffffffff1660e01b8152600401610e4391906121c4565b6101206040518083038186803b158015610e5c57600080fd5b505afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e949190611fae565b60a001518015610f21575060405163cb67e3b160e01b81526001600160a01b0386169063cb67e3b190610ecb908b906004016121c4565b6101206040518083038186803b158015610ee457600080fd5b505afa158015610ef8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1c9190611fae565b60a001515b6040518263ffffffff1660e01b8152600401610f3d919061224d565b604080518083038186803b158015610f5457600080fd5b505afa158015610f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8c9190612138565b915091506000610fa1898988868660016105f8565b90506000610fb48a8989878760006105f8565b9050808211610fc35780610fc5565b815b9a9950505050505050505050565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561100f57600080fd5b505afa158015611023573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110479190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561108057600080fd5b505afa158015611094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b8919061203f565b905061097e8585858460a00151856060015160006105f8565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561110d57600080fd5b505afa158015611121573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111459190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561117e57600080fd5b505afa158015611192573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b6919061203f565b905061097e8585858460a00151856060015160016105f8565b6000806000851160405180604001604052806002815260200161066760f31b8152509061120f5760405162461bcd60e51b8152600401610b089190612268565b506000886001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561124b57600080fd5b505afa15801561125f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112839190611c0c565b6001600160a01b03166376d697608987156040518363ffffffff1660e01b81526004016112b1929190612202565b60206040518083038186803b1580156112c957600080fd5b505afa1580156112dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113019190612120565b9050600081871161131b57611316828861176d565b611325565b611325878361176d565b90506000611337886104188b85611831565b90506000871561134a575087831161134f565b508288115b60008c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561138a57600080fd5b505afa15801561139e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c29190611c0c565b90506000611447826001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561140357600080fd5b505afa158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b919061203f565b61014001518a9061170c565b42116114d357816001600160a01b031663cb67e3b18e6040518263ffffffff1660e01b815260040161147991906121c4565b6101206040518083038186803b15801561149257600080fd5b505afa1580156114a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ca9190611fae565b606001516114d6565b60005b90508280156114f957506114ea8c82611831565b6114f685612710611831565b11155b1561150357600093505b50909c919b50909950505050505050505050565b600081611526575060006108f5565b60006116246127106104186105d68b6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561156d57600080fd5b505afa158015611581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a59190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b1580156115de57600080fd5b505afa1580156115f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611616919061203f565b61010001516127109061176d565b9050611630838261176d565b98975050505050505050565b60008261164b575060006116f9565b60006116d3838a6001600160a01b031663c65bc7b18a6040518263ffffffff1660e01b815260040161167d91906121c4565b60206040518083038186803b15801561169557600080fd5b505afa1580156116a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116cd9190612120565b9061176d565b9050806116e45760009150506116f9565b6116f5620f42406104188684611831565b9150505b979650505050505050565b600192915050565b600082820183811015611766576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000828211156117c4576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808211611820576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161182957fe5b049392505050565b600082611840575060006105ec565b8282028284828161184d57fe5b04146117665760405162461bcd60e51b81526004018080602001828103825260218152602001806124266021913960400191505060405180910390fd5b600080836001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156118c657600080fd5b505afa1580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe9190611c0c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193657600080fd5b505afa15801561194a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196e9190612120565b90508061197f5760009150506105ec565b6000846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156119ba57600080fd5b505afa1580156119ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f29190611c0c565b90506000816001600160a01b031663cb67e3b1866040518263ffffffff1660e01b8152600401611a2291906121c4565b6101206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190611fae565b6040015190506108f5826001600160a01b031663dc8f5fac6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ab557600080fd5b505afa158015611ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aed9190612120565b6104188386611831565b611aff611bbf565b611b07611bbf565b60008060008060008b6001600160a01b0316634a3f088d8c8c8c8c6040518563ffffffff1660e01b8152600401611b4194939291906121d8565b6101006040518083038186803b158015611b5a57600080fd5b505afa158015611b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b92919061215b565b968d5250505060208a01929092526040890152606088015260c087015250939a9950505050505050505050565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8051611c0781612417565b919050565b600060208284031215611c1d578081fd5b8151611766816123ff565b60008060408385031215611c3a578081fd5b8235611c45816123ff565b91506020830135611c55816123ff565b809150509250929050565b60008060408385031215611c72578182fd5b8251611c7d81612417565b6020939093015192949293505050565b60008060408385031215611c3a578182fd5b60008060008060008060c08789031215611cb7578182fd5b8635611cc2816123ff565b95506020870135611cd2816123ff565b94506040870135611ce2816123ff565b93506060870135611cf2816123ff565b92506080870135611d0281612417565b915060a0870135611d1281612417565b809150509295509295509295565b60008060008060008060c08789031215611d38578182fd5b8635611d43816123ff565b95506020870135611d53816123ff565b94506040870135611d63816123ff565b93506060870135611d73816123ff565b92506080870135611d8381612417565b8092505060a087013590509295509295509295565b60008060008060808587031215611dad578081fd5b8435611db8816123ff565b93506020850135611dc8816123ff565b92506040850135611dd8816123ff565b9396929550929360600135925050565b600080600060608486031215611dfc578081fd5b8335611e07816123ff565b92506020840135611e17816123ff565b929592945050506040919091013590565b60008060008060008060c08789031215611e40578384fd5b8635611e4b816123ff565b95506020870135611e5b816123ff565b945060408701359350606087013592506080870135611d8381612417565b60008060008060008060c08789031215611e91578384fd5b8635611e9c816123ff565b95506020870135611eac816123ff565b945060408701359350606087013592506080870135915060a0870135611d1281612417565b600080600080600080600060e0888a031215611eeb578485fd5b8735611ef6816123ff565b96506020880135611f06816123ff565b95506040880135611f16816123ff565b94506060880135611f26816123ff565b93506080880135611f3681612417565b9699959850939692959460a0840135945060c09093013592915050565b60008060008060808587031215611f68578182fd5b8435611f73816123ff565b93506020850135611f83816123ff565b92506040850135611f93816123ff565b91506060850135611fa381612417565b939692955090935050565b6000610120808385031215611fc1578182fd5b611fca816123db565b9050611fd583611bfc565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261200b60a08401611bfc565b60a082015261201c60c08401611bfc565b60c082015260e08381015190820152610100928301519281019290925250919050565b6000610200808385031215612052578182fd5b61205b816123db565b905061206683611bfc565b815261207460208401611bfc565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152506101606120e7818501611bfc565b9082015261018083810151908201526101a080840151908201526101c080840151908201526101e0928301519281019290925250919050565b600060208284031215612131578081fd5b5051919050565b6000806040838503121561214a578182fd5b505080516020909101519092909150565b600080600080600080600080610100898b031215612177578182fd5b885197506020890151965060408901519550606089015194506080890151935060a0890151925060c08901516121ac81612417565b8092505060e089015190509295985092959890939650565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b039590951685526020850193909352604084019190915215156060830152608082015260a00190565b901515815260200190565b9115158252602082015260400190565b6000602080835283518082850152825b8181101561229457858101830151858201604001528201612278565b818111156122a55783604083870101525b50601f01601f1916929092016040019392505050565b60208082526024908201527f5661756c745574696c733a206c6f737365732065786365656420636f6c6c6174604082015263195c985b60e21b606082015260800190565b6020808252818101527f5661756c745574696c733a206d61784c65766572616765206578636565646564604082015260600190565b6020808252602e908201527f5661756c745574696c733a206c69717569646174696f6e20666565732065786360408201526d1959590818dbdb1b185d195c985b60921b606082015260800190565b60208082526022908201527f5661756c745574696c733a20666565732065786365656420636f6c6c61746572604082015261185b60f21b606082015260800190565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156123f757fe5b604052919050565b6001600160a01b038116811461241457600080fd5b50565b801515811461241457600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122033bc8c653222af6d2f972573dfa2c4318ab36f1b37eb278364c92d9a3ef2060964736f6c63430007060033
Deployed ByteCode
0x73686285827f67f13b68baa45c8aa920997f877a0a30146080604052600436106100d85760003560e01c806387e35c2c11610096578063cfb90b2011610070578063cfb90b2014610196578063d4b9aa63146101b7578063dbeac656146101ca578063fbfded6d146101dd576100d8565b806387e35c2c1461015d578063ac56fc0e14610170578063c1a83e2a14610183576100d8565b80628d73e6146100dd578063126082cf1461010657806323a0ec041461010e578063429a429f146101215780634e9c9175146101345780636be6026b14610155575b600080fd5b6100f06100eb366004611c8d565b6101fd565b6040516100fd91906123c4565b60405180910390f35b6100f06105f2565b6100f061011c366004611e79565b6105f8565b6100f061012f366004611f53565b6108ff565b610147610142366004611c9f565b610987565b6040516100fd9291906123cd565b6100f0610d18565b6100f061016b366004611d98565b610d1f565b6100f061017e366004611de8565b610fd3565b6100f0610191366004611de8565b6110d1565b6101a96101a4366004611e28565b6111cf565b6040516100fd929190612258565b6100f06101c5366004611d20565b611517565b6100f06101d8366004611ed1565b61163c565b6101f06101eb366004611c28565b611704565b6040516100fd919061224d565b600080836001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561023957600080fd5b505afa15801561024d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102719190611c0c565b90506000816001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b1580156102af57600080fd5b505afa1580156102c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e7919061203f565b90506000816101a0015190504261037a82856001600160a01b031663d8f897c3896040518263ffffffff1660e01b815260040161032491906121c4565b60206040518083038186803b15801561033c57600080fd5b505afa158015610350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103749190612120565b9061170c565b111561038c57600093505050506105ec565b600061041e82610418866001600160a01b031663d8f897c38a6040518263ffffffff1660e01b81526004016103c191906121c4565b60206040518083038186803b1580156103d957600080fd5b505afa1580156103ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104119190612120565b429061176d565b906117ca565b90506000846001600160a01b03166352f55eed886040518263ffffffff1660e01b815260040161044e91906121c4565b60206040518083038186803b15801561046657600080fd5b505afa15801561047a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049e9190612120565b9050806104b3576000955050505050506105ec565b60405163cb67e3b160e01b81526000906001600160a01b0387169063cb67e3b1906104e2908b906004016121c4565b6101206040518083038186803b1580156104fb57600080fd5b505afa15801561050f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105339190611fae565b60a0015161054657846101c0015161054d565b846101e001515b90506105e382610418856105dd8a6001600160a01b031663c3c7b9e98e6040518263ffffffff1660e01b815260040161058691906121c4565b60206040518083038186803b15801561059e57600080fd5b505afa1580156105b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d69190612120565b8690611831565b90611831565b96505050505050505b92915050565b61271081565b6000866001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561063357600080fd5b505afa158015610647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066b9190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b1580156106a457600080fd5b505afa1580156106b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106dc919061203f565b61016001516106ec5750826108f5565b6000876001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561072757600080fd5b505afa15801561073b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075f9190611c0c565b6001600160a01b03166342e85182886040518263ffffffff1660e01b815260040161078a91906121c4565b60206040518083038186803b1580156107a257600080fd5b505afa1580156107b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107da9190612120565b905060006107e8828861170c565b90508361080b5781871161080557610800828861176d565b610808565b60005b90505b60006108178a8a61188a565b905080610829578693505050506108f5565b60008184116108415761083c828561176d565b61084b565b61084b848361176d565b9050600082841161086557610860838561176d565b61086f565b61086f848461176d565b9050818110156108b1576000610889846104188b86611831565b90508981116108a15761089c8a8261176d565b6108a4565b60005b96505050505050506108f5565b60006108c26002610418858561170c565b9050838111156108cf5750825b60006108df856104188c85611831565b90506108eb8b8261170c565b9750505050505050505b9695505050505050565b60405163c65bc7b160e01b81526000906001600160a01b0386169063c65bc7b19061092e9087906004016121c4565b60206040518083038186803b15801561094657600080fd5b505afa15801561095a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097e9190612120565b95945050505050565b6000806000886001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156109c557600080fd5b505afa1580156109d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fd9190611c0c565b90506000610a0e828a8a8a8a611af7565b805160408083015160c08401519151635c07eaab60e01b815293945060009384936001600160a01b03881693635c07eaab93610a51938f93928f9160040161221d565b604080518083038186803b158015610a6857600080fd5b505afa158015610a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa09190611c60565b915091506000610ad2610abb8e8e8e8e8e8a60000151611517565b610374878f8f8f8f8b600001518c6060015161163c565b905082158015610ae55750818460200151105b15610b21578715610b115760405162461bcd60e51b8152600401610b08906122bb565b60405180910390fd5b600196509450610d0d9350505050565b602084015183610b3d576020850151610b3a908461176d565b90505b81811015610b74578815610b635760405162461bcd60e51b8152600401610b0890612382565b600197509550610d0d945050505050565b60008e6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610baf57600080fd5b505afa158015610bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be79190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b158015610c2057600080fd5b505afa158015610c34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c58919061203f565b9050610c728161012001518461170c90919063ffffffff16565b821015610caa578915610c975760405162461bcd60e51b8152600401610b0890612334565b6001839850985050505050505050610d0d565b8551610cb890612710611831565b6040820151610cc8908490611831565b1015610cff578915610cec5760405162461bcd60e51b8152600401610b08906122ff565b6002839850985050505050505050610d0d565b506000975090955050505050505b965096945050505050565b620f424081565b600080856001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610d5b57600080fd5b505afa158015610d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d939190611c0c565b9050600080876001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610dd157600080fd5b505afa158015610de5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e099190611c0c565b6001600160a01b031663eab4d7a9846001600160a01b031663cb67e3b18a6040518263ffffffff1660e01b8152600401610e4391906121c4565b6101206040518083038186803b158015610e5c57600080fd5b505afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e949190611fae565b60a001518015610f21575060405163cb67e3b160e01b81526001600160a01b0386169063cb67e3b190610ecb908b906004016121c4565b6101206040518083038186803b158015610ee457600080fd5b505afa158015610ef8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1c9190611fae565b60a001515b6040518263ffffffff1660e01b8152600401610f3d919061224d565b604080518083038186803b158015610f5457600080fd5b505afa158015610f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8c9190612138565b915091506000610fa1898988868660016105f8565b90506000610fb48a8989878760006105f8565b9050808211610fc35780610fc5565b815b9a9950505050505050505050565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561100f57600080fd5b505afa158015611023573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110479190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561108057600080fd5b505afa158015611094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b8919061203f565b905061097e8585858460a00151856060015160006105f8565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561110d57600080fd5b505afa158015611121573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111459190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561117e57600080fd5b505afa158015611192573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b6919061203f565b905061097e8585858460a00151856060015160016105f8565b6000806000851160405180604001604052806002815260200161066760f31b8152509061120f5760405162461bcd60e51b8152600401610b089190612268565b506000886001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561124b57600080fd5b505afa15801561125f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112839190611c0c565b6001600160a01b03166376d697608987156040518363ffffffff1660e01b81526004016112b1929190612202565b60206040518083038186803b1580156112c957600080fd5b505afa1580156112dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113019190612120565b9050600081871161131b57611316828861176d565b611325565b611325878361176d565b90506000611337886104188b85611831565b90506000871561134a575087831161134f565b508288115b60008c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561138a57600080fd5b505afa15801561139e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c29190611c0c565b90506000611447826001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561140357600080fd5b505afa158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b919061203f565b61014001518a9061170c565b42116114d357816001600160a01b031663cb67e3b18e6040518263ffffffff1660e01b815260040161147991906121c4565b6101206040518083038186803b15801561149257600080fd5b505afa1580156114a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ca9190611fae565b606001516114d6565b60005b90508280156114f957506114ea8c82611831565b6114f685612710611831565b11155b1561150357600093505b50909c919b50909950505050505050505050565b600081611526575060006108f5565b60006116246127106104186105d68b6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561156d57600080fd5b505afa158015611581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a59190611c0c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b1580156115de57600080fd5b505afa1580156115f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611616919061203f565b61010001516127109061176d565b9050611630838261176d565b98975050505050505050565b60008261164b575060006116f9565b60006116d3838a6001600160a01b031663c65bc7b18a6040518263ffffffff1660e01b815260040161167d91906121c4565b60206040518083038186803b15801561169557600080fd5b505afa1580156116a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116cd9190612120565b9061176d565b9050806116e45760009150506116f9565b6116f5620f42406104188684611831565b9150505b979650505050505050565b600192915050565b600082820183811015611766576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000828211156117c4576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808211611820576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161182957fe5b049392505050565b600082611840575060006105ec565b8282028284828161184d57fe5b04146117665760405162461bcd60e51b81526004018080602001828103825260218152602001806124266021913960400191505060405180910390fd5b600080836001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156118c657600080fd5b505afa1580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe9190611c0c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193657600080fd5b505afa15801561194a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196e9190612120565b90508061197f5760009150506105ec565b6000846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156119ba57600080fd5b505afa1580156119ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f29190611c0c565b90506000816001600160a01b031663cb67e3b1866040518263ffffffff1660e01b8152600401611a2291906121c4565b6101206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190611fae565b6040015190506108f5826001600160a01b031663dc8f5fac6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ab557600080fd5b505afa158015611ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aed9190612120565b6104188386611831565b611aff611bbf565b611b07611bbf565b60008060008060008b6001600160a01b0316634a3f088d8c8c8c8c6040518563ffffffff1660e01b8152600401611b4194939291906121d8565b6101006040518083038186803b158015611b5a57600080fd5b505afa158015611b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b92919061215b565b968d5250505060208a01929092526040890152606088015260c087015250939a9950505050505050505050565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8051611c0781612417565b919050565b600060208284031215611c1d578081fd5b8151611766816123ff565b60008060408385031215611c3a578081fd5b8235611c45816123ff565b91506020830135611c55816123ff565b809150509250929050565b60008060408385031215611c72578182fd5b8251611c7d81612417565b6020939093015192949293505050565b60008060408385031215611c3a578182fd5b60008060008060008060c08789031215611cb7578182fd5b8635611cc2816123ff565b95506020870135611cd2816123ff565b94506040870135611ce2816123ff565b93506060870135611cf2816123ff565b92506080870135611d0281612417565b915060a0870135611d1281612417565b809150509295509295509295565b60008060008060008060c08789031215611d38578182fd5b8635611d43816123ff565b95506020870135611d53816123ff565b94506040870135611d63816123ff565b93506060870135611d73816123ff565b92506080870135611d8381612417565b8092505060a087013590509295509295509295565b60008060008060808587031215611dad578081fd5b8435611db8816123ff565b93506020850135611dc8816123ff565b92506040850135611dd8816123ff565b9396929550929360600135925050565b600080600060608486031215611dfc578081fd5b8335611e07816123ff565b92506020840135611e17816123ff565b929592945050506040919091013590565b60008060008060008060c08789031215611e40578384fd5b8635611e4b816123ff565b95506020870135611e5b816123ff565b945060408701359350606087013592506080870135611d8381612417565b60008060008060008060c08789031215611e91578384fd5b8635611e9c816123ff565b95506020870135611eac816123ff565b945060408701359350606087013592506080870135915060a0870135611d1281612417565b600080600080600080600060e0888a031215611eeb578485fd5b8735611ef6816123ff565b96506020880135611f06816123ff565b95506040880135611f16816123ff565b94506060880135611f26816123ff565b93506080880135611f3681612417565b9699959850939692959460a0840135945060c09093013592915050565b60008060008060808587031215611f68578182fd5b8435611f73816123ff565b93506020850135611f83816123ff565b92506040850135611f93816123ff565b91506060850135611fa381612417565b939692955090935050565b6000610120808385031215611fc1578182fd5b611fca816123db565b9050611fd583611bfc565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261200b60a08401611bfc565b60a082015261201c60c08401611bfc565b60c082015260e08381015190820152610100928301519281019290925250919050565b6000610200808385031215612052578182fd5b61205b816123db565b905061206683611bfc565b815261207460208401611bfc565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152506101606120e7818501611bfc565b9082015261018083810151908201526101a080840151908201526101c080840151908201526101e0928301519281019290925250919050565b600060208284031215612131578081fd5b5051919050565b6000806040838503121561214a578182fd5b505080516020909101519092909150565b600080600080600080600080610100898b031215612177578182fd5b885197506020890151965060408901519550606089015194506080890151935060a0890151925060c08901516121ac81612417565b8092505060e089015190509295985092959890939650565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b039590951685526020850193909352604084019190915215156060830152608082015260a00190565b901515815260200190565b9115158252602082015260400190565b6000602080835283518082850152825b8181101561229457858101830151858201604001528201612278565b818111156122a55783604083870101525b50601f01601f1916929092016040019392505050565b60208082526024908201527f5661756c745574696c733a206c6f737365732065786365656420636f6c6c6174604082015263195c985b60e21b606082015260800190565b6020808252818101527f5661756c745574696c733a206d61784c65766572616765206578636565646564604082015260600190565b6020808252602e908201527f5661756c745574696c733a206c69717569646174696f6e20666565732065786360408201526d1959590818dbdb1b185d195c985b60921b606082015260800190565b60208082526022908201527f5661756c745574696c733a20666565732065786365656420636f6c6c61746572604082015261185b60f21b606082015260800190565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156123f757fe5b604052919050565b6001600160a01b038116811461241457600080fd5b50565b801515811461241457600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122033bc8c653222af6d2f972573dfa2c4318ab36f1b37eb278364c92d9a3ef2060964736f6c63430007060033